blob: 91c45ca7db0905be61af68d7667cfa9286fb5146 [file] [log] [blame]
################################################################################
# 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.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()
self.ticket_limit = config["ticket_limit"].get()
def get_issues(self, jql_query, limit=10000):
"""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
:param limit: the maximum number of issues that should returned
:return: a list of issues matching the query
"""
limit_per_api_request = min(100, limit)
current = 0
total = 1
issues = []
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[: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, 1)
return len(issues) > 0
def add_label_with_comment(self, key, label, comment):
if not self.is_dry_run:
self.jira_client.edit_issue(
key,
{"labels": [{"add": label}], "comment": [{"add": {"body": comment}}]},
)
else:
logging.info(f'DRY RUN ({key}): Adding label "{label}".')
@abc.abstractmethod
def run(self):
return
@abc.abstractmethod
def handle_stale_ticket(self, key, warning_label, done_label, comment):
return
def mark_stale_tickets_stale(self, jql_query):
logging.info(f"Looking for stale tickets.")
issues = self.get_issues(jql_query)
updated_issues_counter = 0
i = 0
while i < len(issues) and updated_issues_counter <= self.ticket_limit:
issue = issues[i]
key = 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_with_comment(key, self.warning_label, formatted_comment)
updated_issues_counter += 1
else:
logging.info(
f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks."
f"Ignoring for now."
)
i += 1
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, self.ticket_limit)
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.handle_stale_ticket(
key, self.warning_label, self.done_label, formatted_comment
)