| |
@@ -45,11 +45,11 @@
|
| |
|
| |
def _comment_format(comment):
|
| |
"""
|
| |
- Function to format JIRA comments
|
| |
- Args:
|
| |
- comment (dict): Upstream comment
|
| |
- Returns:
|
| |
- Response (str): Comments formatted
|
| |
+ Function to format JIRA comments.
|
| |
+
|
| |
+ :param dict comment: Upstream comment
|
| |
+ :returns: Comments formatted
|
| |
+ :rtype: String
|
| |
"""
|
| |
pretty_date = comment['date_created'].strftime("%a %b %d")
|
| |
return "[%s] Upstream, %s wrote [%s]:\n\n{quote}\n%s\n{quote}" % (
|
| |
@@ -60,11 +60,11 @@
|
| |
"""
|
| |
Legacy function to format JIRA comments.
|
| |
This is still used to match comments so no
|
| |
- duplicates are created
|
| |
- Args:
|
| |
- comment (dict): Upstream comment
|
| |
- Returns:
|
| |
- Response (str): Comments formatted
|
| |
+ duplicates are created.
|
| |
+
|
| |
+ :param dict comment: Upstream comment
|
| |
+ :returns: Comments formatted
|
| |
+ :rtype: String
|
| |
"""
|
| |
return "Upstream, %s wrote:\n\n{quote}\n%s\n{quote}" % (
|
| |
comment['name'], comment['body'])
|
| |
@@ -72,12 +72,12 @@
|
| |
|
| |
def _get_jira_client(issue, config):
|
| |
"""
|
| |
- Function to match and create JIRA client
|
| |
- Args:
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- Returns:
|
| |
- client (jira.client.JIRA): Matching JIRA client
|
| |
+ Function to match and create JIRA client.
|
| |
+
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param dict config: Config dict
|
| |
+ :returns: Matching JIRA client
|
| |
+ :rtype: jira.client.JIRA
|
| |
"""
|
| |
# The name of the jira instance to use is stored under the 'map'
|
| |
# key in the config where each upstream is mapped to jira projects.
|
| |
@@ -104,14 +104,14 @@
|
| |
|
| |
def _matching_jira_issue_query(client, issue, config, free=False):
|
| |
"""
|
| |
- API calls that find matching JIRA tickets if any are present
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- free (Bool): Free tag to add 'statusCategory != Done' to query
|
| |
- Returns:
|
| |
- results (lst): Returns a list of matching JIRA issues if any are found
|
| |
+ API calls that find matching JIRA tickets if any are present.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param Dict config: Config dict
|
| |
+ :param Bool free: Free tag to add 'statusCategory != Done' to query
|
| |
+ :returns: results: Returns a list of matching JIRA issues if any are found
|
| |
+ :rtype: List
|
| |
"""
|
| |
# Searches for any remote link to the issue.url
|
| |
query = 'issueFunction in linkedIssuesOfRemote("%s") and ' \
|
| |
@@ -177,15 +177,14 @@
|
| |
def alert_user_of_duplicate_issues(issue, final_result, results_of_query,
|
| |
config, client):
|
| |
"""
|
| |
- Alerts owner of duplicate downstream issues
|
| |
- Args:
|
| |
- issue (sync2jira.intermediate.Issue): Upstream Issue object
|
| |
- final_result (list): Issue selected by matching algorithm
|
| |
- results_of_query (list): Result of JQL query
|
| |
- config (dict): Config dict
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Alerts owner of duplicate downstream issues.
|
| |
+
|
| |
+ :param sync2jira.intermediate.Issue issue: Upstream Issue object
|
| |
+ :param List final_result: Issue selected by matching algorithm
|
| |
+ :param List results_of_query: Result of JQL query
|
| |
+ :param Dict config: Config dict
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# First remove final_result from results_of_query
|
| |
results_of_query.remove(final_result[0])
|
| |
@@ -273,12 +272,12 @@
|
| |
|
| |
def find_username(issue, config):
|
| |
"""
|
| |
- Finds JIRA username for an issue object
|
| |
- Args:
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- Returns:
|
| |
- return (str): Username string
|
| |
+ Finds JIRA username for an issue object.
|
| |
+
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Username string
|
| |
+ :rtype: String
|
| |
"""
|
| |
jira_instance = issue.downstream.get('jira_instance', False)
|
| |
if not jira_instance:
|
| |
@@ -292,16 +291,14 @@
|
| |
def check_comments_for_duplicate(client, result, username):
|
| |
"""
|
| |
Checks comment of JIRA issue to see if it has been
|
| |
- marked as a duplicate
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client)
|
| |
- result (jira.resource.Issue): JIRA issue
|
| |
- username (str): Username of JIRA user
|
| |
- Returns:
|
| |
- return (bool): True if duplicate comment was not found
|
| |
- *Or*
|
| |
- return (jira.resource.Issue): JIRA issue if we were able to
|
| |
- find it
|
| |
+ marked as a duplicate.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client)
|
| |
+ :param jira.resource.Issue result: JIRA issue
|
| |
+ :param string username: Username of JIRA user
|
| |
+ :returns: True if duplicate comment was not found or JIRA issue if \
|
| |
+ we were able to find it
|
| |
+ :rtype: Bool or jira.resource.Issue
|
| |
"""
|
| |
for comment in client.comments(result):
|
| |
search = re.search(r'Marking as duplicate of (\w*)-(\d*)',
|
| |
@@ -314,12 +311,12 @@
|
| |
|
| |
def _find_comment_in_jira(comment, j_comments):
|
| |
"""
|
| |
- Helper function to filter out comments that are matching
|
| |
- Args:
|
| |
- comment (dict): Individual comment from upstream
|
| |
- j_comments (lst(jira.resources.Comment)): Comments from JIRA downstream
|
| |
- Returns:
|
| |
- Item/None (jira.resource.Comment)
|
| |
+ Helper function to filter out comments that are matching.
|
| |
+
|
| |
+ :param Dict comment: Individual comment from upstream
|
| |
+ :param List j_comments: Comments from JIRA downstream
|
| |
+ :returns: Item/None
|
| |
+ :rtype: jira.resource.Comment/None
|
| |
"""
|
| |
formatted_comment = _comment_format(comment)
|
| |
legacy_formatted_comment = _comment_format_legacy(comment)
|
| |
@@ -349,12 +346,12 @@
|
| |
|
| |
def _comment_matching(g_comments, j_comments):
|
| |
"""
|
| |
- Function to filter out comments that are matching
|
| |
- Args:
|
| |
- g_comments (lst(dict)): Comments from Issue object
|
| |
- j_comments (lst(jira.resources.Comment)): Comments from JIRA downstream
|
| |
- Returns:
|
| |
- response (lst): Returns a list of comments that are not matching
|
| |
+ Function to filter out comments that are matching.
|
| |
+
|
| |
+ :param List g_comments: Comments from Issue object
|
| |
+ :param List j_comments: Comments from JIRA downstream
|
| |
+ :returns: Returns a list of comments that are not matching
|
| |
+ :rtype: List
|
| |
"""
|
| |
return list(
|
| |
filter(
|
| |
@@ -366,14 +363,14 @@
|
| |
|
| |
def _get_existing_jira_issue(client, issue, config):
|
| |
"""
|
| |
- Get a jira issue by the linked remote issue.
|
| |
+ Get a jira issue by the linked remote issue. \
|
| |
This is the new supported way of doing this.
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- Returns:
|
| |
- response (lst): Returns a list of matching JIRA issues if any are found
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Returns a list of matching JIRA issues if any are found
|
| |
+ :rtype: List
|
| |
"""
|
| |
results = _matching_jira_issue_query(client, issue, config)
|
| |
if results:
|
| |
@@ -383,9 +380,10 @@
|
| |
|
| |
|
| |
def _get_existing_jira_issue_legacy(client, issue, config):
|
| |
- """ This is our old way of matching issues: use the special url field.
|
| |
-
|
| |
+ """
|
| |
+ This is our old way of matching issues: use the special url field.
|
| |
This will be phased out and removed in a future release.
|
| |
+
|
| |
"""
|
| |
|
| |
kwargs = dict(issue.downstream.items())
|
| |
@@ -405,17 +403,13 @@
|
| |
|
| |
def _attach_link(client, downstream, remote_link):
|
| |
"""
|
| |
- Attaches the upstream link to the JIRA ticket
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- downstream (jira.resources.Issue): Response from
|
| |
- creating the
|
| |
- JIRA ticket
|
| |
- remote_link():
|
| |
- Returns:
|
| |
- downstream (jira.resources.Issue): Response from
|
| |
- creating the
|
| |
- JIRA ticket
|
| |
+ Attaches the upstream link to the JIRA ticket.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param jira.resources.Issue downstream: Response from creating the JIRA ticket
|
| |
+ :param str remote_link: Remote link
|
| |
+ :return: downstream: Response from creating the JIRA ticket
|
| |
+ :rtype: jira.resources.Issue
|
| |
"""
|
| |
log.info(" Attaching tracking link %r to %r", remote_link, downstream.key)
|
| |
modified_desc = downstream.fields.description + " "
|
| |
@@ -438,9 +432,9 @@
|
| |
|
| |
|
| |
def _upgrade_jira_issue(client, downstream, issue, config):
|
| |
- """ Given an old legacy-style downstream issue...
|
| |
+ """
|
| |
+ Given an old legacy-style downstream issue...
|
| |
...upgrade it to a new-style issue.
|
| |
-
|
| |
Simply mark it with an external-url field value.
|
| |
"""
|
| |
log.info(" Upgrading %r %r issue for %r", downstream.key, issue.downstream, issue)
|
| |
@@ -456,15 +450,13 @@
|
| |
def assign_user(client, issue, downstream, remove_all=False):
|
| |
"""
|
| |
Attempts to assigns a JIRA issue to the correct
|
| |
- user based on the issue
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA Client
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- downstream (jira.resources.Issue): JIRA issue object
|
| |
- remove_all (bool): Flag to indicate if we should reset
|
| |
- the assignees in the JIRA issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ user based on the issue.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA Client
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param jira.resources.Issue downstream: JIRA issue object
|
| |
+ :param Bool remove_all: Flag to indicate if we should reset the assignees in the JIRA issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# If removeAll flag, then we need to reset the assignees
|
| |
if remove_all:
|
| |
@@ -500,14 +492,13 @@
|
| |
def _create_jira_issue(client, issue, config):
|
| |
"""
|
| |
Create a JIRA issue and adds all relevant
|
| |
- information in the issue to the JIRA issue
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- Returns:
|
| |
- downstream (jira.resources.Issue): Returns JIRA issue
|
| |
- that was created
|
| |
+ information in the issue to the JIRA issue.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Returns JIRA issue that was created
|
| |
+ :rtype: jira.resources.Issue
|
| |
"""
|
| |
log.info(" Creating %r issue for %r", issue.downstream, issue)
|
| |
if config['sync2jira']['testing']:
|
| |
@@ -560,12 +551,12 @@
|
| |
def _label_matching(jira_labels, issue_labels):
|
| |
"""
|
| |
Filters through jira_labels to ensure no duplicate labels are present and
|
| |
- no jira_labels are removed
|
| |
- Args:
|
| |
- jira_labels (lst(str)): Existing JIRA labels
|
| |
- issue_labels (lst(str): Upstream labels
|
| |
- Returns:
|
| |
- updated_labels (lst(str)): Updated filtered labels
|
| |
+ no jira_labels are removed.
|
| |
+
|
| |
+ :param List jira_labels: Existing JIRA labels
|
| |
+ :param List issue_labels: Upstream labels
|
| |
+ :returns: Updated filtered labels
|
| |
+ :rtype: List
|
| |
"""
|
| |
# We want to get the union of the jira_labels and the issue_labels
|
| |
# i.e. all the labels in jira_labels and no duplicates from issue_labels
|
| |
@@ -576,13 +567,12 @@
|
| |
|
| |
def _update_jira_issue(existing, issue, client):
|
| |
"""
|
| |
- Updates an existing JIRA issue (i.e. tags, assignee, comments etc)
|
| |
- Args:
|
| |
- existing (jira.resources.Issue): Existing JIRA issue that was found
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue we're pulling data from
|
| |
- client (jira.client.JIRA): JIRA Client
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Updates an existing JIRA issue (i.e. tags, assignee, comments etc).
|
| |
+
|
| |
+ :param jira.resources.Issue existing: Existing JIRA issue that was found
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue we're pulling data from
|
| |
+ :param jira.client.JIRA client: JIRA Client
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# Start with comments
|
| |
# Only synchronize comments for listings that op-in
|
| |
@@ -638,13 +628,12 @@
|
| |
|
| |
def _update_transition(client, existing, issue):
|
| |
"""
|
| |
- Helper function to update the transition of a downstream JIRA issue
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function to update the transition of a downstream JIRA issue.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# Update the issue status in the JIRA description
|
| |
# Format the status
|
| |
@@ -702,12 +691,11 @@
|
| |
|
| |
def _update_title(issue, existing):
|
| |
"""
|
| |
- Helper function to sync upstream/downstream title
|
| |
- Args:
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function to sync upstream/downstream title.
|
| |
+
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
new_description = existing.fields.description
|
| |
if not new_description:
|
| |
@@ -750,13 +738,12 @@
|
| |
|
| |
def _update_comments(client, existing, issue):
|
| |
"""
|
| |
- Helper function to sync comments between existing JIRA issue and upstream issue
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function to sync comments between existing JIRA issue and upstream issue.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# First get all existing comments
|
| |
comments = client.comments(existing)
|
| |
@@ -773,13 +760,12 @@
|
| |
|
| |
def _update_fixVersion(updates, existing, issue):
|
| |
"""
|
| |
- Helper function to sync comments between existing JIRA issue and upstream issue
|
| |
- Args:
|
| |
- updates (list): Downstream updates requested by the user
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function to sync comments between existing JIRA issue and upstream issue.
|
| |
+
|
| |
+ :param List updates: Downstream updates requested by the user
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
fix_version = []
|
| |
# If we are not supposed to overwrite JIRA content
|
| |
@@ -827,14 +813,13 @@
|
| |
|
| |
def _update_assignee(client, existing, issue, updates):
|
| |
"""
|
| |
- Helper function update existing JIRA assignee from downstream issue
|
| |
- Args:
|
| |
- client (jira.client.JIRA): JIRA client
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- updates (list): Downstream updates requested by the user
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function update existing JIRA assignee from downstream issue.
|
| |
+
|
| |
+ :param jira.client.JIRA client: JIRA client
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :param List updates: Downstream updates requested by the user
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# First check if overwrite is set to True
|
| |
try:
|
| |
@@ -876,13 +861,12 @@
|
| |
|
| |
def _update_tags(updates, existing, issue):
|
| |
"""
|
| |
- Helper function to sync tags between upstream issue and downstream JIRA issue
|
| |
- Args:
|
| |
- updates (list): Downstream updates requested by the user
|
| |
- existing (jira.resource.Issue): Existing JIRA issue
|
| |
- issue (sync2jira.intermediary.Issue): Upstream issue
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ Helper function to sync tags between upstream issue and downstream JIRA issue.
|
| |
+
|
| |
+ :param List updates: Downstream updates requested by the user
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
# First get all existing tags on the issue
|
| |
updated_labels = issue.tags
|
| |
@@ -908,6 +892,13 @@
|
| |
|
| |
|
| |
def _update_description(existing, issue):
|
| |
+ """
|
| |
+ Helper function to sync description between upstream issue and downstream JIRA issue.
|
| |
+
|
| |
+ :param jira.resource.Issue existing: Existing JIRA issue
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream issue
|
| |
+ :returns: Nothing
|
| |
+ """
|
| |
new_description = existing.fields.description
|
| |
if not new_description:
|
| |
new_description = ''
|
| |
@@ -973,11 +964,11 @@
|
| |
|
| |
def verify_tags(tags):
|
| |
"""
|
| |
- Helper function to ensure tag are JIRA ready :)
|
| |
- Args:
|
| |
- tags (lst(str)): Input tags
|
| |
- Returns:
|
| |
- updated_tags (lst(str)): Updates tags
|
| |
+ Helper function to ensure tag are JIRA ready :).
|
| |
+
|
| |
+ :param List tags: Input tags
|
| |
+ :returns: Updates tags
|
| |
+ :rtype: List
|
| |
"""
|
| |
updated_tags = []
|
| |
for tag in tags:
|
| |
@@ -988,12 +979,11 @@
|
| |
def sync_with_jira(issue, config):
|
| |
"""
|
| |
Attempts to sync a upstream issue with JIRA (i.e. by finding
|
| |
- an existing issue or creating a new one)
|
| |
- Args:
|
| |
- issue (sync2jira.intermediary.Issue): Issue object
|
| |
- config (dict): Config dict
|
| |
- Returns:
|
| |
- Nothing
|
| |
+ an existing issue or creating a new one).
|
| |
+
|
| |
+ :param sync2jira.intermediary.Issue issue: Issue object
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Nothing
|
| |
"""
|
| |
|
| |
log.info(" Considering upstream %s, %s", issue.url, issue.title)
|
| |
@@ -1035,6 +1025,15 @@
|
| |
|
| |
|
| |
def _close_as_duplicate(client, duplicate, keeper, config):
|
| |
+ """
|
| |
+ Helper function to close an issue as a duplicate.
|
| |
+
|
| |
+ :param jira.client client: JIRA Client
|
| |
+ :param jira.resources.Issue duplicate: Duplicate JIRA Issue
|
| |
+ :param jira.resources.Issue keeper: JIRA issue to keep
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Nothing
|
| |
+ """
|
| |
log.info(" Closing %s as duplicate of %s", duplicate.permalink(), keeper.permalink())
|
| |
if config['sync2jira']['testing']:
|
| |
log.info(" Testing flag is true. Skipping actual delete.")
|
| |
@@ -1079,6 +1078,13 @@
|
| |
|
| |
|
| |
def close_duplicates(issue, config):
|
| |
+ """
|
| |
+ Function to close duplicate JIRA issues.
|
| |
+
|
| |
+ :param sync2jira.intermediary.Issue issue: Upstream Issue
|
| |
+ :param Dict config: Config dict
|
| |
+ :returns: Nothing
|
| |
+ """
|
| |
# Create a client connection for this issue
|
| |
client = _get_jira_client(issue, config)
|
| |
|
| |