pycontribs / jira

Python Jira library. Development chat available on https://matrix.to/#/#pycontribs:matrix.org
https://jira.readthedocs.io
BSD 2-Clause "Simplified" License
1.92k stars 859 forks source link

Odd behavior of with `remove_watcher` method of JIRA client: #1734

Open danmanor opened 10 months ago

danmanor commented 10 months ago

Bug summary

Hello,

I have encountered odd behavior from remove_watcher method of JIRA client - When I attempt to remove a watcher from an issue that is no longer an active user on Jira, it raises a jira.JIRAError exception. I humbly believe it shouldn't fail in that case, but just remove the watcher.

Thank you

Is there an existing issue for this?

Jira Instance type

Jira Cloud (Hosted by Atlassian)

Jira instance version

No response

jira-python version

3.5.2

Python Interpreter version

3.11.4

Which operating systems have you used?

Reproduction steps

Remove an inactive watcher user from an issue

Stack trace

jira.exceptions.JIRAError: JiraError HTTP None
12:49:47    text: No matching user found for: <user>

Expected behaviour

Watcher should be removed.

Additional Context

No response

cperrin88 commented 7 months ago

I am not sure what can be done about this. In Jira Cloud the issue/{issueIdOrKey}/watchers endpoint expects an accountId to delete a user. To get the accountId we search for the username on the user/search endpoint. It seems like in this case the endpoint didn't return a user. The only "fix" I could think of would be to add a method that accepts an accountId instead of a username.

tonkolviktor commented 6 months ago

in our setup, with jira==3.6.0, I get:

issue_handler/issue_handler_base.py:199: in issue_handling_engine
    self.ticket_key = self.jira_conn.create_ticket(self._create_ticket_fields(), watcher_list)
services/jira.py:131: in create_ticket
    self._connection.add_watcher(ticket.key, watcher)
../jira/client.py:124: in wrapper
    result = func(*arg_list, **kwargs)
../jira/client.py:2326: in add_watcher
    watcher_id = self._get_user_id(watcher)

    def _get_user_id(self, user: str | None) -> str | None:
        """Internal method for translating a user search (str) to an id.

        Return None and -1 unchanged.

        This function uses :py:meth:`JIRA.search_users` to find the user and then using :py:meth:`JIRA._get_user_identifier` extracts
        the relevant identifier property depending on whether the instance is a Cloud or self-hosted Instance.

        Args:
            user (Optional[str]): The search term used for finding a user. None, '-1' and -1 are equivalent to 'Unassigned'.

        Raises:
            JIRAError: If any error occurs.

        Returns:
            Optional[str]: The Jira user's identifier. Or "-1" and None unchanged.
        """
        if user in (None, -1, "-1"):
            return user
        try:
            user_obj: User
            if self._is_cloud:
                users = self.search_users(query=user, maxResults=20)
            else:
                users = self.search_users(user=user, maxResults=20)

            if len(users) < 1:
                raise JIRAError(f"No matching user found for: '{user}'")

            matches = []
            if len(users) > 1:
                matches = [u for u in users if self._get_user_identifier(u) == user]
            user_obj = matches[0] if matches else users[0]

        except Exception as e:
>           raise JIRAError(str(e))
E           jira.exceptions.JIRAError: JiraError HTTP None
E               text: JiraError HTTP None
E               text: No matching user found for: '5eXXXXXXXX'

../jira/client.py:1853: JIRAError

with jira==3.5.2 it works without issue