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:22 UTC

[flink-jira-bot] branch master updated (a43b94f -> dcb4a44)

This is an automated email from the ASF dual-hosted git repository.

knaufk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/flink-jira-bot.git.


    from a43b94f  Merge pull request #14 from knaufk/FLINK-22570
     new 9c2998a  [hotfix] fix typo in one of the comments
     new 59c16f5  [FLINK-22569] limit number of tickets touched by the bot per run to 100
     new dcb4a44  Merge pull request #15 from knaufk/FLINK-22569

The 47 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 config.yaml        |  7 ++++++-
 flink_jira_rule.py | 17 +++++++++--------
 2 files changed, 15 insertions(+), 9 deletions(-)

[flink-jira-bot] 14/47: [hotfix] fix name of github action

Posted by kn...@apache.org.
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 4bd79cfa90fc4c323c7c09dd58d3e05001af6ba9
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 14 12:12:42 2021 +0200

    [hotfix] fix name of github action
---
 .github/workflows/actions.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml
index 4af2e33..d9ef9fe 100644
--- a/.github/workflows/actions.yaml
+++ b/.github/workflows/actions.yaml
@@ -1,4 +1,4 @@
-name: Run Flink Jira Bot Hourly
+name: Run Flink Jira Twice Daily
 
 on:
   schedule:

[flink-jira-bot] 08/47: [FLINK-22023] add license headers

Posted by kn...@apache.org.
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 3cfda47472ddf6c4efe449b333637a0e578c7593
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 14:34:48 2021 +0200

    [FLINK-22023] add license headers
---
 .gitignore        | 18 ++++++++++++++++++
 Makefile          | 19 +++++++++++++++++++
 config.yaml       | 18 ++++++++++++++++++
 flink_jira_bot.py | 18 ++++++++++++++++++
 requirements.txt  | 18 ++++++++++++++++++
 5 files changed, 91 insertions(+)

diff --git a/.gitignore b/.gitignore
index 5ceb386..4b8ee1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,19 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
 venv
diff --git a/Makefile b/Makefile
index adfff3d..7e2cc73 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,22 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+
 # define the name of the virtual environment directory
 VENV := venv
 
diff --git a/config.yaml b/config.yaml
index 727da38..1afae72 100644
--- a/config.yaml
+++ b/config.yaml
@@ -1,3 +1,21 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
 stale_minor:
     stale_days: 180
     warning_days: 7
diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 05541ca..72f13fe 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -1,3 +1,21 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
 from atlassian import Jira
 import logging
 import confuse
diff --git a/requirements.txt b/requirements.txt
index 336352b..4f3ae54 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,21 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
 appdirs==1.4.4
 atlassian-python-api==3.8.0
 black==20.8b1

[flink-jira-bot] 28/47: [hotfix] pull up logic for marking tickets stale

Posted by kn...@apache.org.
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 b342cb2168b941790ebefd36a780b80cd2c9dc96
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 14:18:09 2021 +0200

    [hotfix] pull up logic for marking tickets stale
---
 flink_jira_rule.py           | 28 ++++++++++++++++++++++++++++
 stale_assigned_rule.py       | 37 ++++---------------------------------
 stale_major_or_above_rule.py | 37 ++++---------------------------------
 stale_minor_rule.py          | 37 ++++---------------------------------
 4 files changed, 40 insertions(+), 99 deletions(-)

diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index c453562..ff32a1e 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -113,3 +113,31 @@ class FlinkJiraRule:
     @abc.abstractmethod
     def run(self):
         return
+
+    def mark_stale_tickets_stale(self, jql_query):
+
+        logging.info(f"Looking for stale tickets.")
+        issues = self.get_issues(jql_query)
+
+        for issue in issues:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                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.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Ignoring for now."
+                )
diff --git a/stale_assigned_rule.py b/stale_assigned_rule.py
index ddee747..cb672d4 100644
--- a/stale_assigned_rule.py
+++ b/stale_assigned_rule.py
@@ -33,7 +33,10 @@ class StaleAssignedRule(FlinkJiraRule):
 
     def run(self):
         self.unassign_tickets_marked_stale()
-        self.mark_stale_tickets_stale()
+        self.mark_stale_tickets_stale(
+            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY "
+            f"AND updated < startOfDay(-{self.stale_days}d)"
+        )
 
     def unassign_tickets_marked_stale(self):
 
@@ -61,35 +64,3 @@ class StaleAssignedRule(FlinkJiraRule):
             self.add_comment(key, formatted_comment)
             self.replace_label(issue, self.warning_label, self.done_label)
             self.unassign(key)
-
-    def mark_stale_tickets_stale(self):
-
-        stale_assigned_tickets = (
-            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY AND updated < "
-            f"startOfDay(-{self.stale_days}d)"
-        )
-        logging.info(f"Looking for assigned tickets, which are stale.")
-        issues = self.get_issues(stale_assigned_tickets)
-
-        for issue in issues:
-            key = issue["key"]
-            issue = self.jira_client.get_issue(key)
-
-            if not self.has_recently_updated_subtask(key, self.stale_days):
-                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.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
-                    f"Ignoring for now."
-                )
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index aeda3f1..e37c9d1 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -39,7 +39,10 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
 
     def run(self):
         self.close_tickets_marked_stale()
-        self.mark_stale_tickets_stale()
+        self.mark_stale_tickets_stale(
+            f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved "
+            f"AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)"
+        )
 
     def close_tickets_marked_stale(self):
 
@@ -67,35 +70,3 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
             self.add_comment(key, formatted_comment)
             self.replace_label(issue, self.warning_label, self.done_label)
             self.set_priority(key, self.LOWER_PRIORITIES[self.priority])
-
-    def mark_stale_tickets_stale(self):
-
-        stale_tickets = (
-            f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved AND assignee is "
-            f"empty AND updated < startOfDay(-{self.stale_days}d)"
-        )
-        logging.info(f"Looking for {self.priority} tickets, which are stale.")
-        issues = self.get_issues(stale_tickets)
-
-        for issue in issues:
-            key = issue["key"]
-            issue = self.jira_client.get_issue(key)
-
-            if not self.has_recently_updated_subtask(key, self.stale_days):
-                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.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
-                    f"Ignoring for now."
-                )
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
index 924f3c3..b06785b 100644
--- a/stale_minor_rule.py
+++ b/stale_minor_rule.py
@@ -33,7 +33,10 @@ class StaleMinorRule(FlinkJiraRule):
 
     def run(self):
         self.close_tickets_marked_stale()
-        self.mark_stale_tickets_stale()
+        self.mark_stale_tickets_stale(
+            f"project = FLINK AND Priority = Minor AND resolution = Unresolved "
+            f"AND updated < startOfDay(-{self.stale_days}d)"
+        )
 
     def close_tickets_marked_stale(self):
 
@@ -61,35 +64,3 @@ class StaleMinorRule(FlinkJiraRule):
             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 < "
-            f"startOfDay(-{self.stale_days}d)"
-        )
-        logging.info(f"Looking for minor tickets, which are stale.")
-        issues = self.get_issues(stale_minor_tickets)
-
-        for issue in issues:
-            key = issue["key"]
-            issue = self.jira_client.get_issue(key)
-
-            if not self.has_recently_updated_subtask(key, self.stale_days):
-                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.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
-                    f"Ignoring for now."
-                )

[flink-jira-bot] 27/47: [hotfix] move config parsing into FlinkJiraRule class

Posted by kn...@apache.org.
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 836ee7d377f7b44a11e0bde9a8231de538772210
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 14:08:28 2021 +0200

    [hotfix] move config parsing into FlinkJiraRule class
---
 flink_jira_bot.py            | 12 +++++++-----
 flink_jira_rule.py           |  7 ++++++-
 stale_assigned_rule.py       |  6 ------
 stale_major_or_above_rule.py | 14 ++++----------
 stale_minor_rule.py          |  6 ------
 5 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 80a58e9..aa1befa 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -62,16 +62,18 @@ if __name__ == "__main__":
         password=os.environ["JIRA_PASSWORD"],
     )
 
-    stale_assigned_rule = StaleAssignedRule(jira, jira_bot_config, args.dryrun)
-    stale_minor_rule = StaleMinorRule(jira, jira_bot_config, args.dryrun)
+    stale_assigned_rule = StaleAssignedRule(
+        jira, jira_bot_config["stale_assigned"], args.dryrun
+    )
+    stale_minor_rule = StaleMinorRule(jira, jira_bot_config["stale_minor"], args.dryrun)
     stale_major_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config, args.dryrun, "Major"
+        jira, jira_bot_config["stale_major"], args.dryrun, "Major"
     )
     stale_critical_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config, args.dryrun, "Critical"
+        jira, jira_bot_config["stale_critical"], args.dryrun, "Critical"
     )
     stale_blocker_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config, args.dryrun, "Blocker"
+        jira, jira_bot_config["stale_blocker"], args.dryrun, "Blocker"
     )
     stale_assigned_rule.run()
     stale_minor_rule.run()
diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index 566fce7..c453562 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -25,8 +25,13 @@ class FlinkJiraRule:
 
     def __init__(self, jira_client, config, is_dry_run):
         self.jira_client = jira_client
-        self.config = config
         self.is_dry_run = is_dry_run
+        self.stale_days = config["stale_days"].get()
+        self.warning_days = config["warning_days"].get()
+        self.warning_label = config["warning_label"].get()
+        self.done_label = config["done_label"].get()
+        self.done_comment = config["done_comment"].get()
+        self.warning_comment = config["warning_comment"].get()
 
     def get_issues(self, jql_query):
         """Queries the JIRA PI for all issues that match the given JQL Query
diff --git a/stale_assigned_rule.py b/stale_assigned_rule.py
index e781a9d..ddee747 100644
--- a/stale_assigned_rule.py
+++ b/stale_assigned_rule.py
@@ -30,12 +30,6 @@ class StaleAssignedRule(FlinkJiraRule):
 
     def __init__(self, jira_client, config, is_dry_run):
         super().__init__(jira_client, config, is_dry_run)
-        self.stale_days = config["stale_assigned"]["stale_days"].get()
-        self.warning_days = config["stale_assigned"]["warning_days"].get()
-        self.warning_label = config["stale_assigned"]["warning_label"].get()
-        self.done_label = config["stale_assigned"]["done_label"].get()
-        self.done_comment = config["stale_assigned"]["done_comment"].get()
-        self.warning_comment = config["stale_assigned"]["warning_comment"].get()
 
     def run(self):
         self.unassign_tickets_marked_stale()
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index de3cb17..aeda3f1 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -33,14 +33,6 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
 
     def __init__(self, jira_client, config, is_dry_run, priority):
         super().__init__(jira_client, config, is_dry_run)
-        self.stale_days = config[f"stale_{priority.lower()}"]["stale_days"].get()
-        self.warning_days = config[f"stale_{priority.lower()}"]["warning_days"].get()
-        self.warning_label = config[f"stale_{priority.lower()}"]["warning_label"].get()
-        self.done_label = config[f"stale_{priority.lower()}"]["done_label"].get()
-        self.done_comment = config[f"stale_{priority.lower()}"]["done_comment"].get()
-        self.warning_comment = config[f"stale_{priority.lower()}"][
-            "warning_comment"
-        ].get()
         self.priority = priority
 
     LOWER_PRIORITIES = {"Blocker": "Critical", "Critical": "Major", "Major": "Minor"}
@@ -78,8 +70,10 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
 
     def mark_stale_tickets_stale(self):
 
-        stale_tickets = f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved AND assignee is " \
-                        f"empty AND updated < startOfDay(-{self.stale_days}d)"
+        stale_tickets = (
+            f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved AND assignee is "
+            f"empty AND updated < startOfDay(-{self.stale_days}d)"
+        )
         logging.info(f"Looking for {self.priority} tickets, which are stale.")
         issues = self.get_issues(stale_tickets)
 
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
index 78f7b8d..924f3c3 100644
--- a/stale_minor_rule.py
+++ b/stale_minor_rule.py
@@ -30,12 +30,6 @@ class StaleMinorRule(FlinkJiraRule):
 
     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.warning_label = config["stale_minor"]["warning_label"].get()
-        self.done_label = config["stale_minor"]["done_label"].get()
-        self.done_comment = config["stale_minor"]["done_comment"].get()
-        self.warning_comment = config["stale_minor"]["warning_comment"].get()
 
     def run(self):
         self.close_tickets_marked_stale()

[flink-jira-bot] 39/47: [hotfix] Make comment language friendly to contributors

Posted by kn...@apache.org.
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 9e049443dedc71c381bb8628991e92a3b538dc5e
Author: Seth Wiesman <sj...@gmail.com>
AuthorDate: Fri Apr 23 11:10:07 2021 -0500

    [hotfix] Make comment language friendly to contributors
    
    Co-authored-by: Konstantin Knauf <me...@konstantin-knauf.de>
    
    This closes #11
---
 config.yaml | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/config.yaml b/config.yaml
index 5f928b3..b472cf2 100644
--- a/config.yaml
+++ b/config.yaml
@@ -20,38 +20,55 @@ stale_assigned:
     stale_days: 14
     warning_days: 7
     warning_label: "stale-assigned"
-    warning_comment: 'This issue is assigned but has not received an update in {stale_days} days so it has been labeled "{warning_label}". If you are still working on the issue or are waiting for feedback from a Committer, please remove the label and optionally provide an update. If you are waiting for feedback, please consider this a reminder *to Committers/Reviewer* to get back to you. If you are no longer working on the issue, please unassign yourself so someone else may work on it. I [...]
     done_label: "auto-unassigned"
-    done_comment: 'This issue was marked "{warning_label}" and has not received an update in {warning_days} days. It is now automatically unassigned. If you are still working on it, you can assign it to yourself again. Please also give an update about the status of the work.'
+    warning_comment: |
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I see this issue is assigned but has not received an update in {stale_days}, so it has been labeled "{warning_label}".
+        If you are still working on the issue, please remove the label and add a comment updating the community on your progress.  If this issue is waiting on feedback, please consider this a reminder to the committer/reviewer. Flink is a very active project, and so we appreciate your patience.
+        If you are no longer working on the issue, please unassign yourself so someone else may work on it. If the "warning_label" label is not removed in {warning_days} days, the issue will be automatically unassigned.
+
+    done_comment: |
+        This issue was marked "{warning_label}" {warning_days} ago and has not received an update. I have automatically removed the current assignee from the issue so others in the community may pick it up. If you are still working on this ticket, please ask a committer to reassign you and provide an update about your current status.
 
 stale_minor:
     stale_days: 180
     warning_days: 7
     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.'
+    warning_comment: |
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I noticed that neither this issue nor its subtasks had updates for {state_days} days, so I labeled it "{warning_label}".  If you are still affected by this bug or are still interested in this issue, please update and remove the label.
+
+    done_comment: |
+        This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so I have gone ahead and closed it.  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.
 
 stale_blocker:
     stale_days: 1
     warning_days: 7
     warning_label: "stale-blocker"
-    warning_comment: 'This Blockers is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is a Blocker, please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
     done_label: "auto-deprioritized-blocker"
-    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually a Blocker, please raise the ticket priority again and assign yourself or revive the public discussion.'
+    warning_comment: |
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I see this issues has been marked as a Blocker but is unassigned and neither itself nor its Sub-Tasks have been updated for {stale_days} days. I have gone ahead and marked it "{warning_label}". If this ticket is a Blocker, please either assign yourself or give an update. Afterwards, please remove the label or in {warning_days} days the issue will be deprioritized.
+
+    done_comment: |
+        This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually a Blocker, please raise the priority and ask a committer to assign you the issue or revive the public discussion.
 
 stale_critical:
     stale_days: 7
     warning_days: 7
     warning_label: "stale-critical"
-    warning_comment: 'This critical issue is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is indeed critical, please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
     done_label: "auto-deprioritized-critical"
-    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually critical, please raise the ticket priority again and assign yourself or revive the public discussion.'
+    warning_comment: |
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I see this issues has been marked as Critical but is unassigned and neither itself nor its Sub-Tasks have been updated for {stale_days} days. I have gone ahead and marked it "{warning_label}". If this ticket is critical, please either assign yourself or give an update. Afterwards, please remove the label or in {warning_days} days the issue will be deprioritized.
+
+    done_comment: |
+        This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually Critical, please raise the priority and ask a committer to assign you the issue or revive the public discussion.
 
 stale_major:
     stale_days: 30
     warning_days: 7
     warning_label: "stale-major"
-    warning_comment: 'This major issue is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is indeed "major", please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
     done_label: "auto-deprioritized-major"
-    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually "major", please raise the ticket priority again and assign yourself or revive the public discussion.'
+    warning_comment: |
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I see this issues has been marked as Major but is unassigned and neither itself nor its Sub-Tasks have been updated for {stale_days} days. I have gone ahead and added a "{warning_label}" to the issue". If this ticket is a Major, please either assign yourself or give an update. Afterwards, please remove the label or in {warning_days} days the issue will be deprioritized.
+
+done_comment: |
+    This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually Major, please raise the priority and ask a committer to assign you the issue or revive the public discussion.

[flink-jira-bot] 29/47: [hotfix] pull up logic to handle stale tickets

Posted by kn...@apache.org.
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 a6002490ef50be5f4b3c103ba80db0d90d307c97
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 14:42:06 2021 +0200

    [hotfix] pull up logic to handle stale tickets
---
 flink_jira_rule.py           | 24 ++++++++++++++++++++++++
 stale_assigned_rule.py       | 33 ++++++---------------------------
 stale_major_or_above_rule.py | 34 +++++++---------------------------
 stale_minor_rule.py          | 34 +++++++---------------------------
 4 files changed, 44 insertions(+), 81 deletions(-)

diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index ff32a1e..f11f275 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -114,6 +114,10 @@ class FlinkJiraRule:
     def run(self):
         return
 
+    @abc.abstractmethod
+    def handle_stale_ticket(self, key):
+        return
+
     def mark_stale_tickets_stale(self, jql_query):
 
         logging.info(f"Looking for stale tickets.")
@@ -141,3 +145,23 @@ class FlinkJiraRule:
                     f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
                     f"Ignoring for now."
                 )
+
+    def handle_tickets_marked_stale(self, jql_query):
+        logging.info(f"Looking for ticket previously marked as {self.warning_label}.")
+        issues = self.get_issues(jql_query)
+
+        for issue in issues:
+            key = issue["key"]
+            logging.info(
+                f"Found https://issues.apache.org/jira/browse/{key}. It is now processed as stale."
+            )
+
+            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.handle_stale_ticket(key)
diff --git a/stale_assigned_rule.py b/stale_assigned_rule.py
index cb672d4..26c7b00 100644
--- a/stale_assigned_rule.py
+++ b/stale_assigned_rule.py
@@ -32,35 +32,14 @@ class StaleAssignedRule(FlinkJiraRule):
         super().__init__(jira_client, config, is_dry_run)
 
     def run(self):
-        self.unassign_tickets_marked_stale()
-        self.mark_stale_tickets_stale(
-            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY "
-            f"AND updated < startOfDay(-{self.stale_days}d)"
-        )
-
-    def unassign_tickets_marked_stale(self):
-
-        assigned_tickets_marked_stale = (
+        self.handle_tickets_marked_stale(
             f"project=FLINK AND resolution = Unresolved AND labels in "
             f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
         )
-        logging.info(
-            f"Looking for assigned tickets, which were previously marked as {self.warning_label}."
+        self.mark_stale_tickets_stale(
+            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY "
+            f"AND updated < startOfDay(-{self.stale_days}d)"
         )
-        issues = self.get_issues(assigned_tickets_marked_stale)
-
-        for issue in issues:
-            key = issue["key"]
-            logging.info(
-                f"Found https://issues.apache.org/jira/browse/{key}. It is now unassigned 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.unassign(key)
+    def handle_stale_ticket(self, key):
+        self.unassign(key)
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index e37c9d1..d5e5663 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -38,35 +38,15 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
     LOWER_PRIORITIES = {"Blocker": "Critical", "Critical": "Major", "Major": "Minor"}
 
     def run(self):
-        self.close_tickets_marked_stale()
+        self.handle_tickets_marked_stale(
+            f"project=FLINK AND Priority = {self.priority} AND resolution = Unresolved "
+            f'AND labels in ("{self.warning_label}") '
+            f"AND updated < startOfDay(-{self.warning_days}d)"
+        )
         self.mark_stale_tickets_stale(
             f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved "
             f"AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)"
         )
 
-    def close_tickets_marked_stale(self):
-
-        tickets_marked_stale = (
-            f"project=FLINK AND Priority = {self.priority} AND resolution = Unresolved AND labels in "
-            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
-        )
-        logging.info(
-            f"Looking for {self.priority} tickets, which were previously marked as {self.warning_label}."
-        )
-        issues = self.get_issues(tickets_marked_stale)
-
-        for issue in issues:
-            key = issue["key"]
-            logging.info(
-                f"Found https://issues.apache.org/jira/browse/{key}. It is now deprioritized 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.set_priority(key, self.LOWER_PRIORITIES[self.priority])
+    def handle_stale_ticket(self, key):
+        self.set_priority(key, self.LOWER_PRIORITIES[self.priority])
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
index b06785b..0bef5d9 100644
--- a/stale_minor_rule.py
+++ b/stale_minor_rule.py
@@ -32,35 +32,15 @@ class StaleMinorRule(FlinkJiraRule):
         super().__init__(jira_client, config, is_dry_run)
 
     def run(self):
-        self.close_tickets_marked_stale()
+        self.handle_tickets_marked_stale(
+            f"project=FLINK AND Priority = Minor AND resolution = Unresolved "
+            f'AND labels in ("{self.warning_label}") '
+            f"AND updated < startOfDay(-{self.warning_days}d)"
+        )
         self.mark_stale_tickets_stale(
             f"project = FLINK AND Priority = Minor AND resolution = Unresolved "
             f"AND updated < startOfDay(-{self.stale_days}d)"
         )
 
-    def close_tickets_marked_stale(self):
-
-        minor_tickets_marked_stale = (
-            f"project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in "
-            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
-        )
-        logging.info(
-            f"Looking for minor tickets, which were previously marked as {self.warning_label}."
-        )
-        issues = self.get_issues(minor_tickets_marked_stale)
-
-        for issue in issues:
-            key = issue["key"]
-            logging.info(
-                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 handle_stale_ticket(self, key):
+        self.close_issue(key)

[flink-jira-bot] 02/47: [FLINK-22032] add Makefile and requirements.txt

Posted by kn...@apache.org.
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 f5aa96e9fddf0607471fc587147db6e7037a198c
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 11:30:03 2021 +0200

    [FLINK-22032] add Makefile and requirements.txt
---
 .gitignore       |  1 +
 Makefile         | 26 ++++++++++++++++++++++++++
 requirements.txt | 19 +++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ceb386
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+venv
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a9c933b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+# define the name of the virtual environment directory
+VENV := venv
+
+# default target, when make executed without arguments
+all: venv
+
+$(VENV)/bin/activate: requirements.txt
+	python3 -m venv $(VENV)
+	./$(VENV)/bin/pip install -r requirements.txt
+
+# venv is a shortcut target
+venv: $(VENV)/bin/activate
+
+run: venv
+	./$(VENV)/bin/python3 flink_jira_bot/flink_jira_bot.py
+
+format: venv
+	./$(VENV)/bin/python3 -m black .
+
+clean:
+	rm -rf $(VENV)
+	find . -type f -name '*.pyc' -delete
+
+
+
+.PHONY: all venv run clean
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..d058698
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,19 @@
+appdirs==1.4.4
+atlassian-python-api==3.8.0
+black @ git+git://github.com/psf/black@e114ef5514e95cb9908b38c2397978f2070c1b0e
+certifi==2020.12.5
+chardet==4.0.0
+click==7.1.2
+Deprecated==1.2.12
+idna==2.10
+mypy-extensions==0.4.3
+oauthlib==3.1.0
+pathspec==0.8.1
+pycparser==2.20
+regex==2021.4.4
+requests==2.25.1
+requests-oauthlib==1.3.0
+six==1.15.0
+toml==0.10.2
+urllib3==1.26.4
+wrapt==1.12.1

[flink-jira-bot] 45/47: [hotfix] fix typo in one of the comments

Posted by kn...@apache.org.
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 9c2998af4f06df151ab2b21252814c20a54a6edf
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Tue May 18 19:15:57 2021 +0200

    [hotfix] fix typo in one of the comments
---
 config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.yaml b/config.yaml
index 2e48bb0..50091da 100644
--- a/config.yaml
+++ b/config.yaml
@@ -35,7 +35,7 @@ stale_minor:
     warning_label: "stale-minor"
     done_label: "auto-closed"
     warning_comment: |
-        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I noticed that neither this issue nor its subtasks had updates for {state_days} days, so I labeled it "{warning_label}".  If you are still affected by this bug or are still interested in this issue, please update and remove the label.
+        I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I noticed that neither this issue nor its subtasks had updates for {stale_days} days, so I labeled it "{warning_label}".  If you are still affected by this bug or are still interested in this issue, please update and remove the label.
 
     done_comment: |
         This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so I have gone ahead and closed it.  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.

[flink-jira-bot] 35/47: [FLINK-22429] exclude Sub-Tasks form stale-major+ and stale-minor rule

Posted by kn...@apache.org.
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 0b403ff3b212008819f53ecfa995e34b58b9b95f
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 23 14:52:41 2021 +0200

    [FLINK-22429] exclude Sub-Tasks form stale-major+ and stale-minor rule
---
 stale_major_or_above_rule.py | 4 ++--
 stale_minor_rule.py          | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index c5509a0..dd256b2 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -41,8 +41,8 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
             f"AND updated < startOfDay(-{self.warning_days}d)"
         )
         self.mark_stale_tickets_stale(
-            f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved "
-            f"AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)"
+            f'project=FLINK AND type != "Sub-Task" AND priority = {self.priority} AND resolution = Unresolved '
+            f'AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)'
         )
 
     def handle_stale_ticket(self, key):
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
index 0bef5d9..ae54dac 100644
--- a/stale_minor_rule.py
+++ b/stale_minor_rule.py
@@ -38,8 +38,8 @@ class StaleMinorRule(FlinkJiraRule):
             f"AND updated < startOfDay(-{self.warning_days}d)"
         )
         self.mark_stale_tickets_stale(
-            f"project = FLINK AND Priority = Minor AND resolution = Unresolved "
-            f"AND updated < startOfDay(-{self.stale_days}d)"
+            f'project = FLINK AND type != "Sub-Task" AND Priority = Minor AND resolution = Unresolved '
+            f'AND updated < startOfDay(-{self.stale_days}d)'
         )
 
     def handle_stale_ticket(self, key):

[flink-jira-bot] 32/47: [FLINK-22036] clarify relationship between README and Confluence page

Posted by kn...@apache.org.
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 c41f7fd44fc860743b5f1b4459724e70bbeb7e46
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Thu Apr 22 11:47:29 2021 +0200

    [FLINK-22036] clarify relationship between README and Confluence page
---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index a91e616..eb3c7b6 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Apache Flink Jira Bot
 
-The Flink Jira enforces some of the rules outlined in [the Apache Flink Confluence](https://cwiki.apache.org/confluence/display/FLINK/Flink+Jira+Process).
+The Flink Jira Bot partially enforces the Apache Flink Jira process. Please see [Apache Flink Jira Process](https://cwiki.apache.org/confluence/display/FLINK/Flink+Jira+Process) for all the guidlines and conventions that we try to follow.
 
 ## Usage
 
@@ -59,4 +59,5 @@ An unresolved Minor ticket without an update for {stale_minor.stale_days} is clo
 
 Apache Flink is an open source project of The Apache Software Foundation (ASF).
 
-Flink is distributed data processing framework with powerful stream and batch processing capabilities. Learn more about Flink at http://flink.apache.org/
\ No newline at end of file
+Flink is a distributed data processing framework with powerful stream and batch processing capabilities. Learn more about Flink at http://flink.apache.org/
+

[flink-jira-bot] 47/47: Merge pull request #15 from knaufk/FLINK-22569

Posted by kn...@apache.org.
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 dcb4a4476e5d332cc62c96786c31a7eebc0cf070
Merge: a43b94f 59c16f5
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed May 19 10:09:15 2021 +0200

    Merge pull request #15 from knaufk/FLINK-22569
    
    [FLINK-22569] limit number of tickets touched by the bot per run to 100

 config.yaml        |  7 ++++++-
 flink_jira_rule.py | 17 +++++++++--------
 2 files changed, 15 insertions(+), 9 deletions(-)

[flink-jira-bot] 46/47: [FLINK-22569] limit number of tickets touched by the bot per run to 100

Posted by kn...@apache.org.
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 59c16f595514c67983965d9580c7c0f45eebcaaf
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Tue May 18 19:16:33 2021 +0200

    [FLINK-22569] limit number of tickets touched by the bot per run to 100
---
 config.yaml        |  5 +++++
 flink_jira_rule.py | 17 +++++++++--------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/config.yaml b/config.yaml
index 50091da..f8aa8cf 100644
--- a/config.yaml
+++ b/config.yaml
@@ -17,6 +17,7 @@
 ################################################################################
 
 stale_assigned:
+    ticket_limit: 10
     stale_days: 14
     warning_days: 7
     warning_label: "stale-assigned"
@@ -30,6 +31,7 @@ stale_assigned:
         This issue was marked "{warning_label}" {warning_days} ago and has not received an update. I have automatically removed the current assignee from the issue so others in the community may pick it up. If you are still working on this ticket, please ask a committer to reassign you and provide an update about your current status.
 
 stale_minor:
+    ticket_limit: 10
     stale_days: 180
     warning_days: 7
     warning_label: "stale-minor"
@@ -41,6 +43,7 @@ stale_minor:
         This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so I have gone ahead and closed it.  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.
 
 stale_blocker:
+    ticket_limit: 5
     stale_days: 1
     warning_days: 7
     warning_label: "stale-blocker"
@@ -52,6 +55,7 @@ stale_blocker:
         This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually a Blocker, please raise the priority and ask a committer to assign you the issue or revive the public discussion.
 
 stale_critical:
+    ticket_limit: 10
     stale_days: 7
     warning_days: 7
     warning_label: "stale-critical"
@@ -63,6 +67,7 @@ stale_critical:
         This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually Critical, please raise the priority and ask a committer to assign you the issue or revive the public discussion.
 
 stale_major:
+    ticket_limit: 15
     stale_days: 30
     warning_days: 7
     warning_label: "stale-major"
diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index 3f784d7..f70ca3d 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -32,8 +32,9 @@ class FlinkJiraRule:
         self.done_label = config["done_label"].get()
         self.done_comment = config["done_comment"].get()
         self.warning_comment = config["warning_comment"].get()
+        self.ticket_limit = config["ticket_limit"].get()
 
-    def get_issues(self, jql_query):
+    def get_issues(self, jql_query, limit):
         """Queries the JIRA PI for all issues that match the given JQL Query
 
         This method is necessary as requests tend to time out if the number of results reaches a certain number.
@@ -41,23 +42,23 @@ class FlinkJiraRule:
         :param jql_query: the search query
         :return: a list of issues matching the query
         """
-        limit = 200
+        limit_per_api_request = min(100, limit)
         current = 0
         total = 1
         issues = []
-        while current < total:
-            response = self.jira_client.jql(jql_query, limit=limit, start=current)
+        while current < min(total, limit):
+            response = self.jira_client.jql(jql_query, limit=limit_per_api_request, start=current)
             total = response["total"]
             issues = issues + response["issues"]
             current = len(issues)
         logging.info(f'"{jql_query}" returned {len(issues)} issues')
-        return issues
+        return issues[:min(limit, len(issues))]
 
     def has_recently_updated_subtask(self, parent, updated_within_days):
         find_subtasks_updated_within = (
             f"parent = {parent}  AND updated > startOfDay(-{updated_within_days}d)"
         )
-        issues = self.get_issues(find_subtasks_updated_within)
+        issues = self.get_issues(find_subtasks_updated_within, 1)
         return len(issues) > 0
 
     def add_label_with_comment(self, key, label, comment):
@@ -80,7 +81,7 @@ class FlinkJiraRule:
     def mark_stale_tickets_stale(self, jql_query):
 
         logging.info(f"Looking for stale tickets.")
-        issues = self.get_issues(jql_query)
+        issues = self.get_issues(jql_query, self.ticket_limit)
 
         for issue in issues:
             key = issue["key"]
@@ -106,7 +107,7 @@ class FlinkJiraRule:
 
     def handle_tickets_marked_stale(self, jql_query):
         logging.info(f"Looking for ticket previously marked as {self.warning_label}.")
-        issues = self.get_issues(jql_query)
+        issues = self.get_issues(jql_query, self.ticket_limit)
 
         for issue in issues:
             key = issue["key"]

[flink-jira-bot] 05/47: [FLINK-22032] add Rule 3 (logging only)

Posted by kn...@apache.org.
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 6f4e13c295cd09789d509db49496956751e7d9cd
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 13:42:42 2021 +0200

    [FLINK-22032] add Rule 3 (logging only)
---
 Makefile          |  2 +-
 README.md         |  0
 config.yaml       |  6 ++++
 flink_jira_bot.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 40ca9f7..677c9cc 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ $(VENV)/bin/activate: requirements.txt
 venv: $(VENV)/bin/activate
 
 run: venv
-	./$(VENV)/bin/python3 flink_jira_bot/flink_jira_bot.py
+	./$(VENV)/bin/python3 flink_jira_bot.py
 
 format: venv
 	./$(VENV)/bin/python3 -m black .
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000..d77f815
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,6 @@
+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.'
+
diff --git a/flink_jira_bot.py b/flink_jira_bot.py
new file mode 100644
index 0000000..a092399
--- /dev/null
+++ b/flink_jira_bot.py
@@ -0,0 +1,90 @@
+from atlassian import Jira
+import logging
+import confuse
+import os
+import abc
+
+
+class FlinkJiraRule:
+    __metaclass__ = abc.ABCMeta
+
+    def __init__(self, jira_client, config):
+        self.jira_client = jira_client
+        self.config = config
+
+    def has_recently_updated_subtask(self, parent, updated_within_days):
+        find_subtasks_updated_within = (
+            f"parent = {parent}  AND updated > startOfDay(-{updated_within_days}d)"
+        )
+        issues = self.jira_client.jql(find_subtasks_updated_within, limit=1)
+        return issues["total"] > 0
+
+    @abc.abstractmethod
+    def run(self):
+        return
+
+
+class Rule3(FlinkJiraRule):
+    def __init__(self, jira_client, config):
+        super().__init__(jira_client, config)
+        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()
+
+    def run(self):
+        self.close_tickets_marked_stale()
+        self.mark_stale_tickets_stale()
+
+    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)'
+        logging.info(
+            f"Looking for minor tickets, which were previously marked as stale: {minor_tickets_marked_stale}"
+        )
+        issues = jira.jql(minor_tickets_marked_stale, limit=10000)
+
+        for issue in issues["issues"]:
+            key = issue["key"]
+            logging.info(
+                f"Found https://issues.apache.org/jira/browse/{key}. It is now closed due to inactivity."
+            )
+
+    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)"
+        logging.info(
+            f"Looking for minor tickets, which are stale: {stale_minor_tickets}"
+        )
+        issues = self.jira_client.jql(stale_minor_tickets, limit=10000)
+
+        for issue in issues["issues"]:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                logging.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}. It is marked stale now."
+                )
+
+            else:
+                logging.debug(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. Ignoring for now."
+                )
+
+
+if __name__ == "__main__":
+
+    logging.getLogger().setLevel(logging.INFO)
+
+    config = confuse.Configuration("flink-jira-bot", __name__)
+    config.set_file("config.yaml")
+
+    jira = Jira(
+        url="https://issues.apache.org/jira",
+        username="flink-jira-bot",
+        password=os.environ["JIRA_PASSWORD"],
+    )
+
+    rule_3 = Rule3(jira, config)
+    rule_3.run()

[flink-jira-bot] 12/47: Merge pull request #2 from knaufk/FLINK-22035

Posted by kn...@apache.org.
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 9afde4761b1d029c638a6067697a3523f179a588
Merge: ad9bbe7 e5fbb13
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed Apr 14 11:25:45 2021 +0200

    Merge pull request #2 from knaufk/FLINK-22035
    
    [FLINK-22035] Add Github Actions

 .github/workflows/actions.yaml | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

[flink-jira-bot] 13/47: [hotfix] activate bot (remove dry-run flag)

Posted by kn...@apache.org.
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 648787f08974abfcc1902b1b65ba25fcd6648c61
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 14 12:10:12 2021 +0200

    [hotfix] activate bot (remove dry-run flag)
---
 .github/workflows/actions.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml
index 0fc9681..4af2e33 100644
--- a/.github/workflows/actions.yaml
+++ b/.github/workflows/actions.yaml
@@ -2,7 +2,7 @@ name: Run Flink Jira Bot Hourly
 
 on:
   schedule:
-      - cron: 33 9,21 * * *
+      - cron: 33 10,22 * * *
 jobs:
   run:
     env:
@@ -22,4 +22,4 @@ jobs:
           pip install -r requirements.txt
       - name: Run Jira Bot
         run: |
-          python flink_jira_bot.py -d
\ No newline at end of file
+          python flink_jira_bot.py
\ No newline at end of file

[flink-jira-bot] 04/47: [FLINK-22032] add confuse for YAML configuration parsing

Posted by kn...@apache.org.
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 c343d837f21aec32cf9696be3db1308c8de70c88
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 11:34:48 2021 +0200

    [FLINK-22032] add confuse for YAML configuration parsing
---
 requirements.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/requirements.txt b/requirements.txt
index d058698..c5e1dd1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,12 +4,14 @@ black @ git+git://github.com/psf/black@e114ef5514e95cb9908b38c2397978f2070c1b0e
 certifi==2020.12.5
 chardet==4.0.0
 click==7.1.2
+confuse==1.4.0
 Deprecated==1.2.12
 idna==2.10
 mypy-extensions==0.4.3
 oauthlib==3.1.0
 pathspec==0.8.1
 pycparser==2.20
+PyYAML==5.4.1
 regex==2021.4.4
 requests==2.25.1
 requests-oauthlib==1.3.0

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

Posted by kn...@apache.org.
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

[flink-jira-bot] 10/47: [FLINK-22035] add simply github action to run bot hourly

Posted by kn...@apache.org.
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 c20522941bf683d33f9d5fabfd8a1ab584f480b8
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Mon Apr 12 15:12:15 2021 +0200

    [FLINK-22035] add simply github action to run bot hourly
---
 .github/workflows/actions.yaml | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml
new file mode 100644
index 0000000..b3dd688
--- /dev/null
+++ b/.github/workflows/actions.yaml
@@ -0,0 +1,25 @@
+name: Run Flink Jira Bot Hourly
+
+on:
+  schedule:
+      - cron: 0 * * * *
+jobs:
+  run:
+    env:
+      JIRA_PASSWORD: ${{ secrets.FLINK_JIRA_BOT_PASSWORD }}
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up Python 3.9
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.9
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install -r requirements.txt
+      - name: Run Jira Bot
+        run: |
+          python flink_jira_bot.py
\ No newline at end of file

[flink-jira-bot] 07/47: [FLINK-22032] add minimal README

Posted by kn...@apache.org.
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 1709d0456fc50530f3b84dd7d2c4a29193b0aaec
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 14:23:23 2021 +0200

    [FLINK-22032] add minimal README
---
 README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/README.md b/README.md
index e69de29..befa400 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,55 @@
+# Apache Flink Jira Bot
+
+The Flink Jira enforces some of the rules outlined in [the Apache Flink Confluence](https://cwiki.apache.org/confluence/display/FLINK/Flink+Jira+Process).
+
+## Usage
+
+```
+./venv/bin/python3 flink_jira_bot.py --help
+usage: flink_jira_bot.py [-h] [-d] [-c CONFIG]
+
+Apache Flink Jira Bot
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -d, --dry-run         no action on Jira, only logging
+  -c CONFIG, --config CONFIG
+                        path to config file (default: config.yaml)
+```
+
+There are also `make` targets for the important actions:
+
+### Run
+```
+make run
+```
+
+### Dry-Run
+
+The dry-run does not make any changes to the Apache Flink Jira, but instead only logs the actions it would do.
+
+```
+make dry-run
+```
+
+### Configuration
+
+Both `make run` and `make dry-run` look for the password of `flink-jira-bot` in an environment variable called `JIRA_PASSWORD`. 
+
+The configuration of the rules can be found in [config.yaml](config.yaml). 
+
+## About the Rules
+
+### Rule 1 (not implemented yet)
+
+### Rule 2 (not implemented yet)
+
+### Rule 3
+
+An unresolved Minor ticket without an update for {stale.minor.stale_days} is closed after a warning period of {stale.minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher priority if the problem insists.
+
+## About Apache Flink
+
+Apache Flink is an open source project of The Apache Software Foundation (ASF).
+
+Flink is distributed data processing framework with powerful stream and batch processing capabilities. Learn more about Flink at http://flink.apache.org/
\ No newline at end of file

[flink-jira-bot] 21/47: Merge pull request #5 from knaufk/FLINK-22033

Posted by kn...@apache.org.
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 8bf7d6a01ffaf4f2b4c3a47b82562f3e71614f82
Merge: 93679d9 77943a1
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Fri Apr 16 11:46:02 2021 +0200

    Merge pull request #5 from knaufk/FLINK-22033
    
    [FLINK-22033] Implementation of Rule 2

 .github/workflows/actions.yaml |   2 +-
 README.md                      |   8 ++-
 config.yaml                    |   8 +++
 flink_jira_bot.py              | 128 ++++++++++++++++++++++++++++++++++++++---
 4 files changed, 134 insertions(+), 12 deletions(-)

[flink-jira-bot] 40/47: [hotfix] fix indentation in config.yaml

Posted by kn...@apache.org.
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 1c4ab41fce24bca9805bd8de405d87be1bddfaa3
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Thu Apr 29 10:16:26 2021 +0200

    [hotfix] fix indentation in config.yaml
---
 config.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.yaml b/config.yaml
index b472cf2..2e48bb0 100644
--- a/config.yaml
+++ b/config.yaml
@@ -70,5 +70,5 @@ stale_major:
     warning_comment: |
         I am the [Flink Jira Bot|https://github.com/apache/flink-jira-bot/] and I help the community manage its development. I see this issues has been marked as Major but is unassigned and neither itself nor its Sub-Tasks have been updated for {stale_days} days. I have gone ahead and added a "{warning_label}" to the issue". If this ticket is a Major, please either assign yourself or give an update. Afterwards, please remove the label or in {warning_days} days the issue will be deprioritized.
 
-done_comment: |
-    This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually Major, please raise the priority and ask a committer to assign you the issue or revive the public discussion.
+    done_comment: |
+        This issue was labeled "{warning_label}" {warning_days} ago and has not received any updates so it is being deprioritized. If this ticket is actually Major, please raise the priority and ask a committer to assign you the issue or revive the public discussion.

[flink-jira-bot] 26/47: [FLINK-22034] add rule for stale major+ tickets

Posted by kn...@apache.org.
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 aa8c557fa1d1623b1c05d9c247fab2dd12a50533
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 13:16:15 2021 +0200

    [FLINK-22034] add rule for stale major+ tickets
---
 config.yaml                  |  23 ++++++++++
 flink_jira_bot.py            |  13 ++++++
 flink_jira_rule.py           |   7 +++
 stale_major_or_above_rule.py | 107 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 150 insertions(+)

diff --git a/config.yaml b/config.yaml
index d1cb3bb..d0e7aff 100644
--- a/config.yaml
+++ b/config.yaml
@@ -32,3 +32,26 @@ stale_minor:
     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.'
 
+stale_blocker:
+    stale_days: 1
+    warning_days: 7
+    warning_label: "stale-blocker"
+    warning_comment: 'This Blockers is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is a Blocker, please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
+    done_label: "auto-deprioritized-blocker"
+    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually a Blocker, please raise the ticket priority again and assign yourself or revive the public discussion.'
+
+stale_critical:
+    stale_days: 7
+    warning_days: 7
+    warning_label: "stale-critical"
+    warning_comment: 'This critical issue is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is indeed critical, please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
+    done_label: "auto-deprioritized-critical"
+    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually critical, please raise the ticket priority again and assign yourself or revive the public discussion.'
+
+stale_major:
+    stale_days: 30
+    warning_days: 7
+    warning_label: "stale-major"
+    warning_comment: 'This major issue is unassigned and itself and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If this ticket is indeed "major", please either assign yourself or give an update. Afterwards, please remove the label. In {warning_days} days the issue will be deprioritized.'
+    done_label: "auto-deprioritized-major"
+    done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is deprioritized now. If this ticket is actually "major", please raise the ticket priority again and assign yourself or revive the public discussion.'
diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 211f855..80a58e9 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -24,6 +24,7 @@ from argparse import ArgumentParser
 from pathlib import Path
 
 from stale_assigned_rule import StaleAssignedRule
+from stale_major_or_above_rule import StaleMajorOrAboveRule
 from stale_minor_rule import StaleMinorRule
 
 
@@ -63,5 +64,17 @@ if __name__ == "__main__":
 
     stale_assigned_rule = StaleAssignedRule(jira, jira_bot_config, args.dryrun)
     stale_minor_rule = StaleMinorRule(jira, jira_bot_config, args.dryrun)
+    stale_major_rule = StaleMajorOrAboveRule(
+        jira, jira_bot_config, args.dryrun, "Major"
+    )
+    stale_critical_rule = StaleMajorOrAboveRule(
+        jira, jira_bot_config, args.dryrun, "Critical"
+    )
+    stale_blocker_rule = StaleMajorOrAboveRule(
+        jira, jira_bot_config, args.dryrun, "Blocker"
+    )
     stale_assigned_rule.run()
     stale_minor_rule.run()
+    stale_major_rule.run()
+    stale_critical_rule.run()
+    stale_blocker_rule.run()
diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index 9960aca..566fce7 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -98,6 +98,13 @@ class FlinkJiraRule:
         else:
             logging.info(f"DRY_RUN (({key})): Unassigning.")
 
+    def set_priority(self, key, priority):
+        if not self.is_dry_run:
+            fields = {"priority": {"name": priority}}
+            self.jira_client.update_issue_field(key, fields)
+        else:
+            logging.info(f"DRY_RUN (({key})): Setting to {priority}")
+
     @abc.abstractmethod
     def run(self):
         return
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
new file mode 100644
index 0000000..de3cb17
--- /dev/null
+++ b/stale_major_or_above_rule.py
@@ -0,0 +1,107 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+import logging
+
+from flink_jira_rule import FlinkJiraRule
+
+
+class StaleMajorOrAboveRule(FlinkJiraRule):
+    """
+    Tickets major and above need an assignee, or an update within {stale_<blocker|critical|major>.stale_days},
+    otherwise the priority will be reduced after a warning period of {stale_<blocker|critical|major>.warning_days} days.
+    An update of on of the Sub-Tasks counts as an update to the ticket.
+    Before this happens the assignee/reporter/watchers are notified that the ticket is about to become stale and will
+    be deprioritized.
+    The time periods before warning differ based on the priority:
+    """
+
+    def __init__(self, jira_client, config, is_dry_run, priority):
+        super().__init__(jira_client, config, is_dry_run)
+        self.stale_days = config[f"stale_{priority.lower()}"]["stale_days"].get()
+        self.warning_days = config[f"stale_{priority.lower()}"]["warning_days"].get()
+        self.warning_label = config[f"stale_{priority.lower()}"]["warning_label"].get()
+        self.done_label = config[f"stale_{priority.lower()}"]["done_label"].get()
+        self.done_comment = config[f"stale_{priority.lower()}"]["done_comment"].get()
+        self.warning_comment = config[f"stale_{priority.lower()}"][
+            "warning_comment"
+        ].get()
+        self.priority = priority
+
+    LOWER_PRIORITIES = {"Blocker": "Critical", "Critical": "Major", "Major": "Minor"}
+
+    def run(self):
+        self.close_tickets_marked_stale()
+        self.mark_stale_tickets_stale()
+
+    def close_tickets_marked_stale(self):
+
+        tickets_marked_stale = (
+            f"project=FLINK AND Priority = {self.priority} AND resolution = Unresolved AND labels in "
+            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
+        )
+        logging.info(
+            f"Looking for {self.priority} tickets, which were previously marked as {self.warning_label}."
+        )
+        issues = self.get_issues(tickets_marked_stale)
+
+        for issue in issues:
+            key = issue["key"]
+            logging.info(
+                f"Found https://issues.apache.org/jira/browse/{key}. It is now deprioritized 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.set_priority(key, self.LOWER_PRIORITIES[self.priority])
+
+    def mark_stale_tickets_stale(self):
+
+        stale_tickets = f"project=FLINK AND priority = {self.priority} AND resolution = Unresolved AND assignee is " \
+                        f"empty AND updated < startOfDay(-{self.stale_days}d)"
+        logging.info(f"Looking for {self.priority} tickets, which are stale.")
+        issues = self.get_issues(stale_tickets)
+
+        for issue in issues:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                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.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Ignoring for now."
+                )

[flink-jira-bot] 37/47: Merge pull request #9 from knaufk/FLINK-22340

Posted by kn...@apache.org.
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 37190da20dd8586b277be0b13face6632706fdc1
Merge: 673419a 723a958
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Fri Apr 23 16:09:08 2021 +0200

    Merge pull request #9 from knaufk/FLINK-22340
    
    [FLINK-22340] adjust stale_assigned role

 config.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

[flink-jira-bot] 42/47: [FLINK-22576] Set status to 'Open' when unassigning

Posted by kn...@apache.org.
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 f185d8654881b1a14ac11f112848aa2b7be75de7
Author: Chesnay Schepler <ch...@apache.org>
AuthorDate: Mon May 10 16:39:25 2021 +0200

    [FLINK-22576] Set status to 'Open' when unassigning
---
 flink_jira_rule.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index f11f275..a98ca71 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -99,6 +99,9 @@ class FlinkJiraRule:
 
     def unassign(self, key):
         if not self.is_dry_run:
+            if self.jira_client.get_issue_status(key) == "In Progress":
+                self.jira_client.assign_issue(key, self.jira_client.username)
+                self.jira_client.set_issue_status(key, "Open")
             self.jira_client.assign_issue(key, None)
         else:
             logging.info(f"DRY_RUN (({key})): Unassigning.")

[flink-jira-bot] 01/47: Initial commit with the ASL

Posted by kn...@apache.org.
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 647197b3f5c1ab663fd81db383d39fc537553437
Author: Robert Metzger <rm...@apache.org>
AuthorDate: Wed Apr 7 20:40:13 2021 +0200

    Initial commit with the ASL
---
 LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

[flink-jira-bot] 22/47: [hotfix] Auto Close issues with resolution "Auto Closed" instead of "Fixed"

Posted by kn...@apache.org.
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 5f209aeda78972c547e477751f235efffecbe545
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 11:03:49 2021 +0200

    [hotfix] Auto Close issues with resolution "Auto Closed" instead of "Fixed"
---
 flink_jira_bot.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 00ce80f..8b46132 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -91,7 +91,9 @@ class FlinkJiraRule:
 
     def close_issue(self, key):
         if not self.is_dry_run:
-            self.jira_client.issue_transition(key, "Closed")
+            self.jira_client.set_issue_status(
+                key, "Closed", fields={"resolution": {"name": "Auto Closed"}}
+            )
         else:
             logging.info(f"DRY_RUN (({key})): Closing.")
 
@@ -112,7 +114,7 @@ class Rule3(FlinkJiraRule):
     {stale_minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher
     priority if the problem insists.
     """
-    
+
     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()

[flink-jira-bot] 34/47: [hotfix] clarify intetion of stale_assigned comment

Posted by kn...@apache.org.
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 723a958982add0cd6957463009ec0bbc7a3bb050
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 23 14:39:09 2021 +0200

    [hotfix] clarify intetion of stale_assigned comment
---
 config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.yaml b/config.yaml
index 9428f9a..5f928b3 100644
--- a/config.yaml
+++ b/config.yaml
@@ -20,7 +20,7 @@ stale_assigned:
     stale_days: 14
     warning_days: 7
     warning_label: "stale-assigned"
-    warning_comment: 'This issue is assigned but has not received an update in {stale_days} days so it has been labeled "{warning_label}". If you are still working on the issue, please give an update and remove the label. If you are no longer working on the issue, please unassign so someone else may work on it. In {warning_days} days the issue will be automatically unassigned.'
+    warning_comment: 'This issue is assigned but has not received an update in {stale_days} days so it has been labeled "{warning_label}". If you are still working on the issue or are waiting for feedback from a Committer, please remove the label and optionally provide an update. If you are waiting for feedback, please consider this a reminder *to Committers/Reviewer* to get back to you. If you are no longer working on the issue, please unassign yourself so someone else may work on it. I [...]
     done_label: "auto-unassigned"
     done_comment: 'This issue was marked "{warning_label}" and has not received an update in {warning_days} days. It is now automatically unassigned. If you are still working on it, you can assign it to yourself again. Please also give an update about the status of the work.'
 

[flink-jira-bot] 11/47: [FLINK-22035] change cron schedule to twice daily, not at the full hour

Posted by kn...@apache.org.
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 e5fbb1388e35f5731b642fe742887e5b36538a4b
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 14 11:19:52 2021 +0200

    [FLINK-22035] change cron schedule to twice daily, not at the full hour
---
 .github/workflows/actions.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml
index b3dd688..0fc9681 100644
--- a/.github/workflows/actions.yaml
+++ b/.github/workflows/actions.yaml
@@ -2,7 +2,7 @@ name: Run Flink Jira Bot Hourly
 
 on:
   schedule:
-      - cron: 0 * * * *
+      - cron: 33 9,21 * * *
 jobs:
   run:
     env:
@@ -22,4 +22,4 @@ jobs:
           pip install -r requirements.txt
       - name: Run Jira Bot
         run: |
-          python flink_jira_bot.py
\ No newline at end of file
+          python flink_jira_bot.py -d
\ No newline at end of file

[flink-jira-bot] 16/47: [hotfix] fix runtime errors & warnings in flink_jira_bot.py

Posted by kn...@apache.org.
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 310b9cc2757e2ee41f0f82b1e0596f9b4cd71864
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 14 17:56:42 2021 +0200

    [hotfix] fix runtime errors & warnings in flink_jira_bot.py
---
 flink_jira_bot.py | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 72f13fe..f67e57e 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -21,7 +21,6 @@ import logging
 import confuse
 import os
 import abc
-import sys
 from argparse import ArgumentParser
 from pathlib import Path
 
@@ -47,7 +46,7 @@ class FlinkJiraRule:
         key = issue["key"]
 
         if not self.is_dry_run:
-            self.jira.update_issue_field(key, fields)
+            self.jira_client.update_issue_field(key, fields)
         else:
             logging.info(f'DRY RUN ({key}): Adding label "{label}".')
 
@@ -58,7 +57,7 @@ class FlinkJiraRule:
         key = issue["key"]
 
         if not self.is_dry_run:
-            self.jira.update_issue_field(key, fields)
+            self.jira_client.update_issue_field(key, fields)
         else:
             logging.info(
                 f'DRY RUN ({key}): Replace label "{old_label}" for "{new_label}".'
@@ -66,13 +65,13 @@ class FlinkJiraRule:
 
     def add_comment(self, key, comment):
         if not self.is_dry_run:
-            jira.issue_add_comment(key, comment)
+            self.jira_client.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")
+            self.jira_client.issue_transition(key, "Closed")
         else:
             logging.info(f"DRY_RUN (({key})): Closing.")
 
@@ -88,6 +87,7 @@ class Rule3(FlinkJiraRule):
         self.warning_days = config["stale_minor"]["warning_days"].get()
         self.warning_label = config["stale_minor"]["warning_label"].get()
         self.done_label = config["stale_minor"]["done_label"].get()
+        self.done_comment = config["stale_minor"]["done_comment"].get()
         self.warning_comment = config["stale_minor"]["warning_comment"].get()
 
     def run(self):
@@ -96,7 +96,10 @@ 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.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
+        minor_tickets_marked_stale = (
+            f"project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in "
+            f'("{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}"
         )
@@ -120,7 +123,10 @@ class Rule3(FlinkJiraRule):
 
     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)"
+        stale_minor_tickets = (
+            f"project = FLINK AND Priority = Minor AND resolution = Unresolved AND updated < "
+            f"startOfDay(-{self.stale_days}d)"
+        )
         logging.info(
             f"Looking for minor tickets, which are stale: {stale_minor_tickets}"
         )
@@ -145,15 +151,11 @@ class Rule3(FlinkJiraRule):
 
             else:
                 logging.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. Ignoring for now."
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"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(
@@ -179,8 +181,8 @@ if __name__ == "__main__":
 
     args = get_args()
 
-    config = confuse.Configuration("flink-jira-bot", __name__)
-    config.set_file(args.config)
+    jira_bot_config = confuse.Configuration("flink-jira-bot", __name__)
+    jira_bot_config.set_file(args.config)
 
     jira = Jira(
         url="https://issues.apache.org/jira",
@@ -188,5 +190,5 @@ if __name__ == "__main__":
         password=os.environ["JIRA_PASSWORD"],
     )
 
-    rule_3 = Rule3(jira, config, args.dryrun)
+    rule_3 = Rule3(jira, jira_bot_config, args.dryrun)
     rule_3.run()

[flink-jira-bot] 23/47: Merge pull request #6 from knaufk/FLINK-22394

Posted by kn...@apache.org.
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 1bd0618237096e87cd08c827552e46f5325d5637
Merge: 8bf7d6a 5f209ae
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed Apr 21 13:01:32 2021 +0200

    Merge pull request #6 from knaufk/FLINK-22394
    
    [hotfix] Auto Close issues with resolution "Auto Closed" instead of "…

 flink_jira_bot.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

[flink-jira-bot] 36/47: Merge pull request #10 from knaufk/FLINK-22429

Posted by kn...@apache.org.
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 673419a672b02d6f83b2c13e9aded14f153eebd0
Merge: dfb2fd8 0b403ff
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Fri Apr 23 15:52:54 2021 +0200

    Merge pull request #10 from knaufk/FLINK-22429
    
    [FLINK-22429] exclude Sub-Tasks form stale-major+ and stale-minor rule

 stale_major_or_above_rule.py | 4 ++--
 stale_minor_rule.py          | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

[flink-jira-bot] 18/47: [hotfix] fix tyop in Github Actions workflow

Posted by kn...@apache.org.
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 e575ac6695ea89176fb68e9526b5200be57afa2c
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Thu Apr 15 18:21:11 2021 +0200

    [hotfix] fix tyop in Github Actions workflow
---
 .github/workflows/actions.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml
index d9ef9fe..1cc051b 100644
--- a/.github/workflows/actions.yaml
+++ b/.github/workflows/actions.yaml
@@ -1,4 +1,4 @@
-name: Run Flink Jira Twice Daily
+name: Run Flink Jira Bot Twice Daily
 
 on:
   schedule:

[flink-jira-bot] 19/47: [FLINK-22033] add rule 2, which unassign stale assigned tickets after some time

Posted by kn...@apache.org.
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 a38d571a76c617d222e3fab5488c0ffe6d44119f
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 16 10:57:55 2021 +0200

    [FLINK-22033] add rule 2, which unassign stale assigned tickets after some time
---
 README.md         |   8 ++--
 config.yaml       |   8 ++++
 flink_jira_bot.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 121 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
index befa400..503a762 100644
--- a/README.md
+++ b/README.md
@@ -42,11 +42,13 @@ The configuration of the rules can be found in [config.yaml](config.yaml).
 
 ### Rule 1 (not implemented yet)
 
-### Rule 2 (not implemented yet)
+### Rule 2: Unassign Stale Assigned Tickets
 
-### Rule 3
+Assigned tickets without an update for {stale_assigned.stale_days} are unassigned after a warning period of {stale_assigned.warning_days}. Before this happens the assignee is notified that this is about to happen and asked for an update on the status of her contribution.
 
-An unresolved Minor ticket without an update for {stale.minor.stale_days} is closed after a warning period of {stale.minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher priority if the problem insists.
+### Rule 3: Close Stale Minor Tickets
+
+An unresolved Minor ticket without an update for {stale_minor.stale_days} is closed after a warning period of {stale_minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher priority if the problem insists.
 
 ## About Apache Flink
 
diff --git a/config.yaml b/config.yaml
index 1afae72..d1cb3bb 100644
--- a/config.yaml
+++ b/config.yaml
@@ -16,6 +16,14 @@
 # limitations under the License.
 ################################################################################
 
+stale_assigned:
+    stale_days: 7
+    warning_days: 7
+    warning_label: "stale-assigned"
+    warning_comment: 'This issue is assigned but has not received an update in {stale_days} days so it has been labeled "{warning_label}". If you are still working on the issue, please give an update and remove the label. If you are no longer working on the issue, please unassign so someone else may work on it. In {warning_days} days the issue will be automatically unassigned.'
+    done_label: "auto-unassigned"
+    done_comment: 'This issue was marked "{warning_label}" and has not received an update in {warning_days} days. It is now automatically unassigned. If you are still working on it, you can assign it to yourself again. Please also give an update about the status of the work.'
+
 stale_minor:
     stale_days: 180
     warning_days: 7
diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index f67e57e..e1cdc28 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -33,12 +33,32 @@ class FlinkJiraRule:
         self.config = config
         self.is_dry_run = is_dry_run
 
+    def get_issues(self, jql_query):
+        """Queries the JIRA PI for all issues that match the given JQL Query
+
+        This method is necessary as requests tend to time out if the number of results reaches a certain number.
+        So, this method requests the results in multiple queries and returns a final list of all issues.
+        :param jql_query: the search query
+        :return: a list of issues matching the query
+        """
+        limit = 200
+        current = 0
+        total = 1
+        issues = []
+        while current < total:
+            response = self.jira_client.jql(jql_query, limit=limit, start=current)
+            total = response["total"]
+            issues = issues + response["issues"]
+            current = len(issues)
+        logging.info(f'"{jql_query}" returned {len(issues)} issues')
+        return issues
+
     def has_recently_updated_subtask(self, parent, updated_within_days):
         find_subtasks_updated_within = (
             f"parent = {parent}  AND updated > startOfDay(-{updated_within_days}d)"
         )
-        issues = self.jira_client.jql(find_subtasks_updated_within, limit=1)
-        return issues["total"] > 0
+        issues = self.get_issues(find_subtasks_updated_within)
+        return len(issues) > 0
 
     def add_label(self, issue, label):
         labels = issue["fields"]["labels"] + [label]
@@ -75,6 +95,12 @@ class FlinkJiraRule:
         else:
             logging.info(f"DRY_RUN (({key})): Closing.")
 
+    def unassign(self, key):
+        if not self.is_dry_run:
+            self.jira_client.assign_issue(key, None)
+        else:
+            logging.info(f"DRY_RUN (({key})): Unassigning.")
+
     @abc.abstractmethod
     def run(self):
         return
@@ -101,11 +127,11 @@ class Rule3(FlinkJiraRule):
             f'("{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}"
+            f"Looking for minor tickets, which were previously marked as {self.warning_label}."
         )
-        issues = jira.jql(minor_tickets_marked_stale, limit=10000)
+        issues = self.get_issues(minor_tickets_marked_stale)
 
-        for issue in issues["issues"]:
+        for issue in issues:
             key = issue["key"]
             logging.info(
                 f"Found https://issues.apache.org/jira/browse/{key}. It is now closed due to inactivity."
@@ -127,12 +153,84 @@ class Rule3(FlinkJiraRule):
             f"project = FLINK AND Priority = Minor AND resolution = Unresolved AND updated < "
             f"startOfDay(-{self.stale_days}d)"
         )
+        logging.info(f"Looking for minor tickets, which are stale.")
+        issues = self.get_issues(stale_minor_tickets)
+
+        for issue in issues:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                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.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Ignoring for now."
+                )
+
+
+class Rule2(FlinkJiraRule):
+    def __init__(self, jira_client, config, is_dry_run):
+        super().__init__(jira_client, config, is_dry_run)
+        self.stale_days = config["stale_assigned"]["stale_days"].get()
+        self.warning_days = config["stale_assigned"]["warning_days"].get()
+        self.warning_label = config["stale_assigned"]["warning_label"].get()
+        self.done_label = config["stale_assigned"]["done_label"].get()
+        self.done_comment = config["stale_assigned"]["done_comment"].get()
+        self.warning_comment = config["stale_assigned"]["warning_comment"].get()
+
+    def run(self):
+        self.unassign_tickets_marked_stale()
+        self.mark_stale_tickets_stale()
+
+    def unassign_tickets_marked_stale(self):
+
+        assigned_tickets_marked_stale = (
+            f"project=FLINK AND resolution = Unresolved AND labels in "
+            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
+        )
         logging.info(
-            f"Looking for minor tickets, which are stale: {stale_minor_tickets}"
+            f"Looking for assigned tickets, which were previously marked as {self.warning_label}."
+        )
+        issues = self.get_issues(assigned_tickets_marked_stale)
+
+        for issue in issues:
+            key = issue["key"]
+            logging.info(
+                f"Found https://issues.apache.org/jira/browse/{key}. It is now unassigned 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.unassign(key)
+
+    def mark_stale_tickets_stale(self):
+
+        stale_assigned_tickets = (
+            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY AND updated < "
+            f"startOfDay(-{self.stale_days}d)"
         )
-        issues = self.jira_client.jql(stale_minor_tickets, limit=10000)
+        logging.info(f"Looking for assigned tickets, which are stale.")
+        issues = self.get_issues(stale_assigned_tickets)
 
-        for issue in issues["issues"]:
+        for issue in issues:
             key = issue["key"]
             issue = self.jira_client.get_issue(key)
 
@@ -190,5 +288,7 @@ if __name__ == "__main__":
         password=os.environ["JIRA_PASSWORD"],
     )
 
+    rule_2 = Rule2(jira, jira_bot_config, args.dryrun)
     rule_3 = Rule3(jira, jira_bot_config, args.dryrun)
+    rule_2.run()
     rule_3.run()

[flink-jira-bot] 41/47: Merge pull request #12 from knaufk/hotfix-config-formatting

Posted by kn...@apache.org.
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 fe3c5db836bbfd7b8311b1d865fdf0b4d79c192f
Merge: 9e04944 1c4ab41
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Thu Apr 29 10:23:48 2021 +0200

    Merge pull request #12 from knaufk/hotfix-config-formatting
    
    [hotfix] fix indentation in config.yaml

 config.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

[flink-jira-bot] 15/47: Merge pull request #3 from knaufk/activate-bot

Posted by kn...@apache.org.
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 4cc0b90f655950c42dc06e4555631eb40ee51f42
Merge: 9afde47 4bd79cf
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed Apr 14 12:13:15 2021 +0200

    Merge pull request #3 from knaufk/activate-bot
    
    [hotfix] activate bot (remove dry-run flag)

 .github/workflows/actions.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

[flink-jira-bot] 31/47: Merge pull request #7 from knaufk/FLINK-22034

Posted by kn...@apache.org.
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 dfb2fd88a3625d059a03f2b310395b5a58c452e2
Merge: 1bd0618 3fcb3ff
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Thu Apr 22 11:06:05 2021 +0200

    Merge pull request #7 from knaufk/FLINK-22034
    
    [Flink-22034] Implement Rule 1 (and cleanup)

 .gitignore                   |   1 +
 README.md                    |   7 +-
 config.yaml                  |  23 ++++
 flink_jira_bot.py            | 268 ++++---------------------------------------
 flink_jira_rule.py           | 167 +++++++++++++++++++++++++++
 stale_assigned_rule.py       |  45 ++++++++
 stale_major_or_above_rule.py |  49 ++++++++
 stale_minor_rule.py          |  46 ++++++++
 8 files changed, 358 insertions(+), 248 deletions(-)

[flink-jira-bot] 44/47: Merge pull request #14 from knaufk/FLINK-22570

Posted by kn...@apache.org.
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 a43b94fbe084d9e9a6ddab4bfc7feba1f447300c
Merge: f185d86 7cccb04
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed May 19 10:07:44 2021 +0200

    Merge pull request #14 from knaufk/FLINK-22570
    
    [FLINK-22570] combine jira client calls and reduce number of notifica…

 flink_jira_rule.py           | 65 +++++++-------------------------------------
 stale_assigned_rule.py       | 25 +++++++++++++++--
 stale_major_or_above_rule.py | 20 ++++++++++++--
 stale_minor_rule.py          | 22 +++++++++++++--
 4 files changed, 69 insertions(+), 63 deletions(-)

[flink-jira-bot] 09/47: Merge pull request #1 from knaufk/FLINK-22032

Posted by kn...@apache.org.
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 ad9bbe7575797603b95e63ccfecfa13f4d68dac0
Merge: 647197b 3cfda47
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Mon Apr 12 18:02:41 2021 +0200

    Merge pull request #1 from knaufk/FLINK-22032
    
    [Flink-22032] Adding Bot with Initial Rule

 .gitignore        |  19 ++++++
 Makefile          |  54 +++++++++++++++
 README.md         |  55 ++++++++++++++++
 config.yaml       |  26 ++++++++
 flink_jira_bot.py | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 requirements.txt  |  41 ++++++++++++
 6 files changed, 387 insertions(+)

[flink-jira-bot] 38/47: Merge pull request #8 from knaufk/FLINK-22036

Posted by kn...@apache.org.
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 67b61dc4dc756459d3e442f158516d32eec82c0e
Merge: 37190da c41f7fd
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Mon Apr 26 10:35:40 2021 +0200

    Merge pull request #8 from knaufk/FLINK-22036
    
    [FLINK-22036] clarify relationship between README and Confluence page

 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

[flink-jira-bot] 43/47: [FLINK-22570] combine jira client calls and reduce number of notifications to one per ticket per rule

Posted by kn...@apache.org.
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 7cccb045fb9a53d1e8d5b72a644099b0a90bc08d
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Tue May 18 19:03:50 2021 +0200

    [FLINK-22570] combine jira client calls and reduce number of notifications to one per ticket per rule
---
 flink_jira_rule.py           | 65 +++++++-------------------------------------
 stale_assigned_rule.py       | 25 +++++++++++++++--
 stale_major_or_above_rule.py | 20 ++++++++++++--
 stale_minor_rule.py          | 22 +++++++++++++--
 4 files changed, 69 insertions(+), 63 deletions(-)

diff --git a/flink_jira_rule.py b/flink_jira_rule.py
index a98ca71..3f784d7 100644
--- a/flink_jira_rule.py
+++ b/flink_jira_rule.py
@@ -60,58 +60,14 @@ class FlinkJiraRule:
         issues = self.get_issues(find_subtasks_updated_within)
         return len(issues) > 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_client.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_client.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):
+    def add_label_with_comment(self, key, label, comment):
         if not self.is_dry_run:
-            self.jira_client.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:
-            self.jira_client.set_issue_status(
-                key, "Closed", fields={"resolution": {"name": "Auto Closed"}}
+            self.jira_client.edit_issue(
+                key,
+                {"labels": [{"add": label}], "comment": [{"add": {"body": comment}}]},
             )
         else:
-            logging.info(f"DRY_RUN (({key})): Closing.")
-
-    def unassign(self, key):
-        if not self.is_dry_run:
-            if self.jira_client.get_issue_status(key) == "In Progress":
-                self.jira_client.assign_issue(key, self.jira_client.username)
-                self.jira_client.set_issue_status(key, "Open")
-            self.jira_client.assign_issue(key, None)
-        else:
-            logging.info(f"DRY_RUN (({key})): Unassigning.")
-
-    def set_priority(self, key, priority):
-        if not self.is_dry_run:
-            fields = {"priority": {"name": priority}}
-            self.jira_client.update_issue_field(key, fields)
-        else:
-            logging.info(f"DRY_RUN (({key})): Setting to {priority}")
+            logging.info(f'DRY RUN ({key}): Adding label "{label}".')
 
     @abc.abstractmethod
     def run(self):
@@ -140,12 +96,11 @@ class FlinkJiraRule:
                     warning_label=self.warning_label,
                 )
 
-                self.add_label(issue, self.warning_label)
-                self.add_comment(key, formatted_comment)
+                self.add_label_with_comment(key, self.warning_label, formatted_comment)
 
             else:
                 logging.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks."
                     f"Ignoring for now."
                 )
 
@@ -165,6 +120,6 @@ class FlinkJiraRule:
                 done_label=self.done_label,
             )
 
-            self.add_comment(key, formatted_comment)
-            self.replace_label(issue, self.warning_label, self.done_label)
-            self.handle_stale_ticket(key)
+            self.handle_stale_ticket(
+                key, self.warning_label, self.done_label, formatted_comment
+            )
diff --git a/stale_assigned_rule.py b/stale_assigned_rule.py
index 26c7b00..d5cb41c 100644
--- a/stale_assigned_rule.py
+++ b/stale_assigned_rule.py
@@ -41,5 +41,26 @@ class StaleAssignedRule(FlinkJiraRule):
             f"AND updated < startOfDay(-{self.stale_days}d)"
         )
 
-    def handle_stale_ticket(self, key):
-        self.unassign(key)
+    def handle_stale_ticket(self, key, warning_label, done_label, comment):
+        self.unassign(key, warning_label, done_label, comment)
+
+    def unassign(self, key, warning_label, done_label, comment):
+        if not self.is_dry_run:
+            if self.jira_client.get_issue_status(key) == "In Progress":
+                self.jira_client.edit_issue(
+                    key,
+                    {"assignee": [{"set": {"name": self.jira_client.username}}]},
+                    notify_users=False,
+                )
+                self.jira_client.set_issue_status(key, "Open")
+            self.jira_client.edit_issue(
+                key,
+                {
+                    "labels": [{"add": done_label}, {"remove": warning_label}],
+                    "comment": [{"add": {"body": comment}}],
+                    "assignee": [{"set": {"name": None}}],
+                },
+                notify_users=False,
+            )
+        else:
+            logging.info(f"DRY_RUN (({key})): Unassigning.")
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index dd256b2..52aa2ad 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -17,6 +17,7 @@
 ################################################################################
 
 from flink_jira_rule import FlinkJiraRule
+import logging
 
 
 class StaleMajorOrAboveRule(FlinkJiraRule):
@@ -42,8 +43,21 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
         )
         self.mark_stale_tickets_stale(
             f'project=FLINK AND type != "Sub-Task" AND priority = {self.priority} AND resolution = Unresolved '
-            f'AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)'
+            f"AND assignee is empty AND updated < startOfDay(-{self.stale_days}d)"
         )
 
-    def handle_stale_ticket(self, key):
-        self.set_priority(key, self.lower_priority)
+    def handle_stale_ticket(self, key, warning_label, done_label, comment):
+        self.set_priority(key, warning_label, done_label, self.lower_priority, comment)
+
+    def set_priority(self, key, warning_label, done_label, priority, comment):
+        if not self.is_dry_run:
+            self.jira_client.edit_issue(
+                key,
+                {
+                    "labels": [{"add": done_label}, {"remove": warning_label}],
+                    "comment": [{"add": {"body": comment}}],
+                    "priority": [{"set": {"name": priority}}],
+                },
+            )
+        else:
+            logging.info(f"DRY_RUN (({key})): Setting to {priority}")
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
index ae54dac..15bc2cf 100644
--- a/stale_minor_rule.py
+++ b/stale_minor_rule.py
@@ -39,8 +39,24 @@ class StaleMinorRule(FlinkJiraRule):
         )
         self.mark_stale_tickets_stale(
             f'project = FLINK AND type != "Sub-Task" AND Priority = Minor AND resolution = Unresolved '
-            f'AND updated < startOfDay(-{self.stale_days}d)'
+            f"AND updated < startOfDay(-{self.stale_days}d)"
         )
 
-    def handle_stale_ticket(self, key):
-        self.close_issue(key)
+    def handle_stale_ticket(self, key, warning_label, done_label, comment):
+        self.close_issue(key, warning_label, done_label, comment)
+
+    def close_issue(self, key, warning_label, done_label, comment):
+        if not self.is_dry_run:
+            self.jira_client.edit_issue(
+                key,
+                {"labels": [{"add": done_label}, {"remove": warning_label}]},
+                notify_users=False,
+            )
+            self.jira_client.set_issue_status(
+                key,
+                "Closed",
+                fields={"resolution": {"name": "Auto Closed"}},
+                update={"comment": [{"add": {"body": comment}}]},
+            )
+        else:
+            logging.info(f"DRY_RUN (({key})): Closing.")

[flink-jira-bot] 20/47: [FLINK-22033] add docstring for rule classes

Posted by kn...@apache.org.
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 77943a14746fbcdb8432863b07f0c8143d33f3fc
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 16 11:31:51 2021 +0200

    [FLINK-22033] add docstring for rule classes
---
 flink_jira_bot.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index e1cdc28..00ce80f 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -107,6 +107,12 @@ class FlinkJiraRule:
 
 
 class Rule3(FlinkJiraRule):
+    """
+    An unresolved Minor ticket without an update for {stale_minor.stale_days} is closed after a warning period of
+    {stale_minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher
+    priority if the problem insists.
+    """
+    
     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()
@@ -181,6 +187,12 @@ class Rule3(FlinkJiraRule):
 
 
 class Rule2(FlinkJiraRule):
+    """
+    Assigned tickets without an update for {stale_assigned.stale_days} are unassigned after a warning period of
+    {stale_assigned.warning_days}. Before this happens the assignee is notified that this is about to happen and
+    asked for an update on the status of her contribution.
+    """
+
     def __init__(self, jira_client, config, is_dry_run):
         super().__init__(jira_client, config, is_dry_run)
         self.stale_days = config["stale_assigned"]["stale_days"].get()

[flink-jira-bot] 33/47: [FLINK-22340] set stale_assigned.stale_days to 14

Posted by kn...@apache.org.
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 0b934ae3036d494f830d80db41bb639b6b25c41b
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 23 14:33:15 2021 +0200

    [FLINK-22340] set stale_assigned.stale_days to 14
---
 config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.yaml b/config.yaml
index d0e7aff..9428f9a 100644
--- a/config.yaml
+++ b/config.yaml
@@ -17,7 +17,7 @@
 ################################################################################
 
 stale_assigned:
-    stale_days: 7
+    stale_days: 14
     warning_days: 7
     warning_label: "stale-assigned"
     warning_comment: 'This issue is assigned but has not received an update in {stale_days} days so it has been labeled "{warning_label}". If you are still working on the issue, please give an update and remove the label. If you are no longer working on the issue, please unassign so someone else may work on it. In {warning_days} days the issue will be automatically unassigned.'

[flink-jira-bot] 03/47: [FINK-22032] add freeze target to Makefile

Posted by kn...@apache.org.
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 bf4c4c1144ce3f9f7fca5cccb8ce05b8541efe28
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Fri Apr 9 11:34:34 2021 +0200

    [FINK-22032] add freeze target to Makefile
---
 Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Makefile b/Makefile
index a9c933b..40ca9f7 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,9 @@ run: venv
 format: venv
 	./$(VENV)/bin/python3 -m black .
 
+freeze: venv
+	./$(VENV)/bin/pip freeze > requirements.txt
+
 clean:
 	rm -rf $(VENV)
 	find . -type f -name '*.pyc' -delete

[flink-jira-bot] 17/47: Merge pull request #4 from knaufk/hotfix-jira

Posted by kn...@apache.org.
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 93679d9fdd56cc6c0fd2850f08637bf5d8299a5e
Merge: 4cc0b90 310b9cc
Author: Konstantin Knauf <me...@konstantin-knauf.de>
AuthorDate: Wed Apr 14 19:42:56 2021 +0200

    Merge pull request #4 from knaufk/hotfix-jira
    
    [hotfix] fix runtime errors in flink_jira_bot.py

 flink_jira_bot.py | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

[flink-jira-bot] 24/47: [FLIINK-22034] update README.md for Rule1

Posted by kn...@apache.org.
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 5ad9bd36bf13078c8d2ad1b87ca02da3ab9eb6c2
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 11:14:53 2021 +0200

    [FLIINK-22034] update README.md for Rule1
---
 README.md | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 503a762..a91e616 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,12 @@ The configuration of the rules can be found in [config.yaml](config.yaml).
 
 ## About the Rules
 
-### Rule 1 (not implemented yet)
+### Rule 1 Major+ Need Assignee or Discussion
+
+Tickets major and above need an assignee, or an update within {stale_<blocker|critical|major>.stale_days}, otherwise the priority will be reduced after a warning period of {stale_<blocker|critical|major>.warning_days} days.
+An update of a Sub-Task counts as an update to the ticket. 
+Before this happens the assignee/reporter/watchers are notified that the ticket is about to become stale and will be deprioritized. 
+The time periods before warning differ based on the priority: 
 
 ### Rule 2: Unassign Stale Assigned Tickets
 

[flink-jira-bot] 25/47: [hotfix] give rule classes more descriptive names and refactor to separate files

Posted by kn...@apache.org.
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 425f75f6f56e35e3fe91a7f2804c02e26fd895f3
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Wed Apr 21 11:16:15 2021 +0200

    [hotfix] give rule classes more descriptive names and refactor to separate files
---
 .gitignore             |   1 +
 flink_jira_bot.py      | 253 ++-----------------------------------------------
 flink_jira_rule.py     | 103 ++++++++++++++++++++
 stale_assigned_rule.py | 101 ++++++++++++++++++++
 stale_minor_rule.py    | 101 ++++++++++++++++++++
 5 files changed, 312 insertions(+), 247 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4b8ee1e..2d85626 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@
 ################################################################################
 
 venv
+__pycache__
diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index 8b46132..211f855 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -20,252 +20,11 @@ from atlassian import Jira
 import logging
 import confuse
 import os
-import abc
 from argparse import ArgumentParser
 from pathlib import Path
 
-
-class FlinkJiraRule:
-    __metaclass__ = abc.ABCMeta
-
-    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 get_issues(self, jql_query):
-        """Queries the JIRA PI for all issues that match the given JQL Query
-
-        This method is necessary as requests tend to time out if the number of results reaches a certain number.
-        So, this method requests the results in multiple queries and returns a final list of all issues.
-        :param jql_query: the search query
-        :return: a list of issues matching the query
-        """
-        limit = 200
-        current = 0
-        total = 1
-        issues = []
-        while current < total:
-            response = self.jira_client.jql(jql_query, limit=limit, start=current)
-            total = response["total"]
-            issues = issues + response["issues"]
-            current = len(issues)
-        logging.info(f'"{jql_query}" returned {len(issues)} issues')
-        return issues
-
-    def has_recently_updated_subtask(self, parent, updated_within_days):
-        find_subtasks_updated_within = (
-            f"parent = {parent}  AND updated > startOfDay(-{updated_within_days}d)"
-        )
-        issues = self.get_issues(find_subtasks_updated_within)
-        return len(issues) > 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_client.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_client.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:
-            self.jira_client.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:
-            self.jira_client.set_issue_status(
-                key, "Closed", fields={"resolution": {"name": "Auto Closed"}}
-            )
-        else:
-            logging.info(f"DRY_RUN (({key})): Closing.")
-
-    def unassign(self, key):
-        if not self.is_dry_run:
-            self.jira_client.assign_issue(key, None)
-        else:
-            logging.info(f"DRY_RUN (({key})): Unassigning.")
-
-    @abc.abstractmethod
-    def run(self):
-        return
-
-
-class Rule3(FlinkJiraRule):
-    """
-    An unresolved Minor ticket without an update for {stale_minor.stale_days} is closed after a warning period of
-    {stale_minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher
-    priority if the problem insists.
-    """
-
-    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.warning_label = config["stale_minor"]["warning_label"].get()
-        self.done_label = config["stale_minor"]["done_label"].get()
-        self.done_comment = config["stale_minor"]["done_comment"].get()
-        self.warning_comment = config["stale_minor"]["warning_comment"].get()
-
-    def run(self):
-        self.close_tickets_marked_stale()
-        self.mark_stale_tickets_stale()
-
-    def close_tickets_marked_stale(self):
-
-        minor_tickets_marked_stale = (
-            f"project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in "
-            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
-        )
-        logging.info(
-            f"Looking for minor tickets, which were previously marked as {self.warning_label}."
-        )
-        issues = self.get_issues(minor_tickets_marked_stale)
-
-        for issue in issues:
-            key = issue["key"]
-            logging.info(
-                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 < "
-            f"startOfDay(-{self.stale_days}d)"
-        )
-        logging.info(f"Looking for minor tickets, which are stale.")
-        issues = self.get_issues(stale_minor_tickets)
-
-        for issue in issues:
-            key = issue["key"]
-            issue = self.jira_client.get_issue(key)
-
-            if not self.has_recently_updated_subtask(key, self.stale_days):
-                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.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
-                    f"Ignoring for now."
-                )
-
-
-class Rule2(FlinkJiraRule):
-    """
-    Assigned tickets without an update for {stale_assigned.stale_days} are unassigned after a warning period of
-    {stale_assigned.warning_days}. Before this happens the assignee is notified that this is about to happen and
-    asked for an update on the status of her contribution.
-    """
-
-    def __init__(self, jira_client, config, is_dry_run):
-        super().__init__(jira_client, config, is_dry_run)
-        self.stale_days = config["stale_assigned"]["stale_days"].get()
-        self.warning_days = config["stale_assigned"]["warning_days"].get()
-        self.warning_label = config["stale_assigned"]["warning_label"].get()
-        self.done_label = config["stale_assigned"]["done_label"].get()
-        self.done_comment = config["stale_assigned"]["done_comment"].get()
-        self.warning_comment = config["stale_assigned"]["warning_comment"].get()
-
-    def run(self):
-        self.unassign_tickets_marked_stale()
-        self.mark_stale_tickets_stale()
-
-    def unassign_tickets_marked_stale(self):
-
-        assigned_tickets_marked_stale = (
-            f"project=FLINK AND resolution = Unresolved AND labels in "
-            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
-        )
-        logging.info(
-            f"Looking for assigned tickets, which were previously marked as {self.warning_label}."
-        )
-        issues = self.get_issues(assigned_tickets_marked_stale)
-
-        for issue in issues:
-            key = issue["key"]
-            logging.info(
-                f"Found https://issues.apache.org/jira/browse/{key}. It is now unassigned 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.unassign(key)
-
-    def mark_stale_tickets_stale(self):
-
-        stale_assigned_tickets = (
-            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY AND updated < "
-            f"startOfDay(-{self.stale_days}d)"
-        )
-        logging.info(f"Looking for assigned tickets, which are stale.")
-        issues = self.get_issues(stale_assigned_tickets)
-
-        for issue in issues:
-            key = issue["key"]
-            issue = self.jira_client.get_issue(key)
-
-            if not self.has_recently_updated_subtask(key, self.stale_days):
-                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.info(
-                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
-                    f"Ignoring for now."
-                )
+from stale_assigned_rule import StaleAssignedRule
+from stale_minor_rule import StaleMinorRule
 
 
 def get_args():
@@ -302,7 +61,7 @@ if __name__ == "__main__":
         password=os.environ["JIRA_PASSWORD"],
     )
 
-    rule_2 = Rule2(jira, jira_bot_config, args.dryrun)
-    rule_3 = Rule3(jira, jira_bot_config, args.dryrun)
-    rule_2.run()
-    rule_3.run()
+    stale_assigned_rule = StaleAssignedRule(jira, jira_bot_config, args.dryrun)
+    stale_minor_rule = StaleMinorRule(jira, jira_bot_config, args.dryrun)
+    stale_assigned_rule.run()
+    stale_minor_rule.run()
diff --git a/flink_jira_rule.py b/flink_jira_rule.py
new file mode 100644
index 0000000..9960aca
--- /dev/null
+++ b/flink_jira_rule.py
@@ -0,0 +1,103 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+import abc
+import logging
+
+
+class FlinkJiraRule:
+    __metaclass__ = abc.ABCMeta
+
+    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 get_issues(self, jql_query):
+        """Queries the JIRA PI for all issues that match the given JQL Query
+
+        This method is necessary as requests tend to time out if the number of results reaches a certain number.
+        So, this method requests the results in multiple queries and returns a final list of all issues.
+        :param jql_query: the search query
+        :return: a list of issues matching the query
+        """
+        limit = 200
+        current = 0
+        total = 1
+        issues = []
+        while current < total:
+            response = self.jira_client.jql(jql_query, limit=limit, start=current)
+            total = response["total"]
+            issues = issues + response["issues"]
+            current = len(issues)
+        logging.info(f'"{jql_query}" returned {len(issues)} issues')
+        return issues
+
+    def has_recently_updated_subtask(self, parent, updated_within_days):
+        find_subtasks_updated_within = (
+            f"parent = {parent}  AND updated > startOfDay(-{updated_within_days}d)"
+        )
+        issues = self.get_issues(find_subtasks_updated_within)
+        return len(issues) > 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_client.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_client.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:
+            self.jira_client.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:
+            self.jira_client.set_issue_status(
+                key, "Closed", fields={"resolution": {"name": "Auto Closed"}}
+            )
+        else:
+            logging.info(f"DRY_RUN (({key})): Closing.")
+
+    def unassign(self, key):
+        if not self.is_dry_run:
+            self.jira_client.assign_issue(key, None)
+        else:
+            logging.info(f"DRY_RUN (({key})): Unassigning.")
+
+    @abc.abstractmethod
+    def run(self):
+        return
diff --git a/stale_assigned_rule.py b/stale_assigned_rule.py
new file mode 100644
index 0000000..e781a9d
--- /dev/null
+++ b/stale_assigned_rule.py
@@ -0,0 +1,101 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+import logging
+
+from flink_jira_rule import FlinkJiraRule
+
+
+class StaleAssignedRule(FlinkJiraRule):
+    """
+    Assigned tickets without an update for {stale_assigned.stale_days} are unassigned after a warning period of
+    {stale_assigned.warning_days}. Before this happens the assignee is notified that this is about to happen and
+    asked for an update on the status of her contribution.
+    """
+
+    def __init__(self, jira_client, config, is_dry_run):
+        super().__init__(jira_client, config, is_dry_run)
+        self.stale_days = config["stale_assigned"]["stale_days"].get()
+        self.warning_days = config["stale_assigned"]["warning_days"].get()
+        self.warning_label = config["stale_assigned"]["warning_label"].get()
+        self.done_label = config["stale_assigned"]["done_label"].get()
+        self.done_comment = config["stale_assigned"]["done_comment"].get()
+        self.warning_comment = config["stale_assigned"]["warning_comment"].get()
+
+    def run(self):
+        self.unassign_tickets_marked_stale()
+        self.mark_stale_tickets_stale()
+
+    def unassign_tickets_marked_stale(self):
+
+        assigned_tickets_marked_stale = (
+            f"project=FLINK AND resolution = Unresolved AND labels in "
+            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
+        )
+        logging.info(
+            f"Looking for assigned tickets, which were previously marked as {self.warning_label}."
+        )
+        issues = self.get_issues(assigned_tickets_marked_stale)
+
+        for issue in issues:
+            key = issue["key"]
+            logging.info(
+                f"Found https://issues.apache.org/jira/browse/{key}. It is now unassigned 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.unassign(key)
+
+    def mark_stale_tickets_stale(self):
+
+        stale_assigned_tickets = (
+            f"project = FLINK AND resolution = Unresolved AND assignee is not EMPTY AND updated < "
+            f"startOfDay(-{self.stale_days}d)"
+        )
+        logging.info(f"Looking for assigned tickets, which are stale.")
+        issues = self.get_issues(stale_assigned_tickets)
+
+        for issue in issues:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                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.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Ignoring for now."
+                )
diff --git a/stale_minor_rule.py b/stale_minor_rule.py
new file mode 100644
index 0000000..78f7b8d
--- /dev/null
+++ b/stale_minor_rule.py
@@ -0,0 +1,101 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+import logging
+
+from flink_jira_rule import FlinkJiraRule
+
+
+class StaleMinorRule(FlinkJiraRule):
+    """
+    An unresolved Minor ticket without an update for {stale_minor.stale_days} is closed after a warning period of
+    {stale_minor.warning_days} with a comment that encourages users to watch, comment and simply reopen with a higher
+    priority if the problem insists.
+    """
+
+    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.warning_label = config["stale_minor"]["warning_label"].get()
+        self.done_label = config["stale_minor"]["done_label"].get()
+        self.done_comment = config["stale_minor"]["done_comment"].get()
+        self.warning_comment = config["stale_minor"]["warning_comment"].get()
+
+    def run(self):
+        self.close_tickets_marked_stale()
+        self.mark_stale_tickets_stale()
+
+    def close_tickets_marked_stale(self):
+
+        minor_tickets_marked_stale = (
+            f"project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in "
+            f'("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)'
+        )
+        logging.info(
+            f"Looking for minor tickets, which were previously marked as {self.warning_label}."
+        )
+        issues = self.get_issues(minor_tickets_marked_stale)
+
+        for issue in issues:
+            key = issue["key"]
+            logging.info(
+                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 < "
+            f"startOfDay(-{self.stale_days}d)"
+        )
+        logging.info(f"Looking for minor tickets, which are stale.")
+        issues = self.get_issues(stale_minor_tickets)
+
+        for issue in issues:
+            key = issue["key"]
+            issue = self.jira_client.get_issue(key)
+
+            if not self.has_recently_updated_subtask(key, self.stale_days):
+                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.info(
+                    f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. "
+                    f"Ignoring for now."
+                )

[flink-jira-bot] 30/47: [FLINK-22034] get rid of LOWER_PRIORITIES constant

Posted by kn...@apache.org.
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 3fcb3fff062c80d08c22c816836d600155e009af
Author: Konstantin Knauf <kn...@gmail.com>
AuthorDate: Thu Apr 22 10:54:11 2021 +0200

    [FLINK-22034] get rid of LOWER_PRIORITIES constant
---
 flink_jira_bot.py            | 6 +++---
 stale_major_or_above_rule.py | 9 +++------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/flink_jira_bot.py b/flink_jira_bot.py
index aa1befa..36f8ca0 100644
--- a/flink_jira_bot.py
+++ b/flink_jira_bot.py
@@ -67,13 +67,13 @@ if __name__ == "__main__":
     )
     stale_minor_rule = StaleMinorRule(jira, jira_bot_config["stale_minor"], args.dryrun)
     stale_major_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config["stale_major"], args.dryrun, "Major"
+        jira, jira_bot_config["stale_major"], args.dryrun, "Major", "Minor"
     )
     stale_critical_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config["stale_critical"], args.dryrun, "Critical"
+        jira, jira_bot_config["stale_critical"], args.dryrun, "Critical", "Major"
     )
     stale_blocker_rule = StaleMajorOrAboveRule(
-        jira, jira_bot_config["stale_blocker"], args.dryrun, "Blocker"
+        jira, jira_bot_config["stale_blocker"], args.dryrun, "Blocker", "Critical"
     )
     stale_assigned_rule.run()
     stale_minor_rule.run()
diff --git a/stale_major_or_above_rule.py b/stale_major_or_above_rule.py
index d5e5663..c5509a0 100644
--- a/stale_major_or_above_rule.py
+++ b/stale_major_or_above_rule.py
@@ -16,8 +16,6 @@
 # limitations under the License.
 ################################################################################
 
-import logging
-
 from flink_jira_rule import FlinkJiraRule
 
 
@@ -31,12 +29,11 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
     The time periods before warning differ based on the priority:
     """
 
-    def __init__(self, jira_client, config, is_dry_run, priority):
+    def __init__(self, jira_client, config, is_dry_run, priority, lower_priority):
         super().__init__(jira_client, config, is_dry_run)
+        self.lower_priority = lower_priority
         self.priority = priority
 
-    LOWER_PRIORITIES = {"Blocker": "Critical", "Critical": "Major", "Major": "Minor"}
-
     def run(self):
         self.handle_tickets_marked_stale(
             f"project=FLINK AND Priority = {self.priority} AND resolution = Unresolved "
@@ -49,4 +46,4 @@ class StaleMajorOrAboveRule(FlinkJiraRule):
         )
 
     def handle_stale_ticket(self, key):
-        self.set_priority(key, self.LOWER_PRIORITIES[self.priority])
+        self.set_priority(key, self.lower_priority)