22import  re 
33from  dataclasses  import  dataclass 
44from  datetime  import  UTC , datetime 
5+ from  typing  import  Any 
56from  urllib .parse  import  quote 
67
78import  discord 
2223
2324REPOSITORY_ENDPOINT  =  "https://api.github.com/orgs/{org}/repos?per_page=100&type=public" 
2425ISSUE_ENDPOINT  =  "https://api.github.com/repos/{user}/{repository}/issues/{number}" 
25- PR_ENDPOINT  =  "https://api.github.com/repos/{user}/{repository}/pulls/{number}" 
2626
2727if  Tokens .github :
2828    REQUEST_HEADERS ["Authorization" ] =  f"token { Tokens .github .get_secret_value ()}  
@@ -83,19 +83,13 @@ def remove_codeblocks(message: str) -> str:
8383        """Remove any codeblock in a message.""" 
8484        return  CODE_BLOCK_RE .sub ("" , message )
8585
86-     async  def  fetch_issue (
87-         self ,
88-         number : int ,
89-         repository : str ,
90-         user : str 
91-     ) ->  IssueState  |  FetchError :
86+     async  def  fetch_issue (self , number : int , repository : str , user : str ) ->  IssueState  |  FetchError :
9287        """ 
9388        Retrieve an issue from a GitHub repository. 
9489
9590        Returns IssueState on success, FetchError on failure. 
9691        """ 
9792        url  =  ISSUE_ENDPOINT .format (user = user , repository = repository , number = number )
98-         pulls_url  =  PR_ENDPOINT .format (user = user , repository = repository , number = number )
9993
10094        json_data , r  =  await  self .fetch_data (url )
10195
@@ -109,35 +103,44 @@ async def fetch_issue(
109103        if  r .status  !=  200 :
110104            return  FetchError (r .status , "Error while fetching issue." )
111105
112-         # The initial API request is made to the issues API endpoint, which will return information 
113-         # if the issue or PR is present. However, the scope of information returned for PRs differs 
114-         # from issues: if the 'issues' key is present in the response then we can pull the data we 
115-         # need from the initial API call. 
116-         if  "issues"  in  json_data ["html_url" ]:
117-             emoji  =  Emojis .issue_open 
118-             if  json_data .get ("state" ) ==  "closed" :
119-                 emoji  =  Emojis .issue_completed 
120-             if  json_data .get ("state_reason" ) ==  "not_planned" :
121-                 emoji  =  Emojis .issue_not_planned 
122- 
123-         # If the 'issues' key is not contained in the API response and there is no error code, then 
124-         # we know that a PR has been requested and a call to the pulls API endpoint is necessary 
125-         # to get the desired information for the PR. 
126-         else :
127-             pull_data , _  =  await  self .fetch_data (pulls_url )
128-             if  pull_data ["draft" ]:
106+         # its important to note that the issues endpoint only provides issues and pull requests 
107+         # discussions are not supported, but may still be provided 
108+         # this method doesn't check for discussions, it just silently ignores them 
109+         log .trace ("Fetched issue/PR data: %r" , json_data )
110+         if  pull_data  :=  json_data .get ("pull_request" ):
111+             if  pull_data .get ("merged_at" ):
112+                 emoji  =  Emojis .pull_request_merged 
113+             elif  json_data .get ("draft" ) is  True :
129114                emoji  =  Emojis .pull_request_draft 
130-             elif  pull_data [ "state" ]  ==  "open" :
115+             elif  json_data . get ( "state" )  ==  "open" :
131116                emoji  =  Emojis .pull_request_open 
132-             # When 'merged_at' is not None, this means that the state of the PR is merged 
133-             elif  pull_data ["merged_at" ] is  not None :
134-                 emoji  =  Emojis .pull_request_merged 
135-             else :
117+             elif  json_data .get ("state" ) ==  "closed" :
136118                emoji  =  Emojis .pull_request_closed 
119+             else :
120+                 # unknown state, GitHub added a new state and the emoji should be added 
121+                 log .error ("Unknown PR state: %s for %s" , json_data .get ("state" ), url )
122+                 # fall the emoji back to a state 
123+                 emoji  =  Emojis .pull_request_open 
124+         else :
125+             if  json_data .get ("state" ) ==  "closed" :
126+                 if  json_data .get ("state_reason" ) ==  "not_planned" :
127+                     emoji  =  Emojis .issue_not_planned 
128+                 else :
129+                     emoji  =  Emojis .issue_completed 
130+             elif  json_data .get ("draft" ) is  True :
131+                 # not currently used by GitHub, but future planning 
132+                 emoji  =  Emojis .issue_draft 
133+             elif  json_data .get ("state" ) ==  "open" :
134+                 emoji  =  Emojis .issue_open 
135+             else :
136+                 # unknown state, GitHub added a new state and the emoji should be added 
137+                 log .error ("Unknown issue state: %s for %s" , json_data .get ("state" ), url )
138+                 # fall the emoji back to a state 
139+                 emoji  =  Emojis .issue_open 
137140
138-         issue_url  =  json_data . get ( "html_url" ) 
141+         html_url  =  json_data [ "html_url" ] 
139142
140-         return  IssueState (repository , number , issue_url , json_data .get ("title" , "" ), emoji )
143+         return  IssueState (repository , number , html_url , json_data .get ("title" , "" ), emoji )
141144
142145    @staticmethod  
143146    def  format_embed (
@@ -217,7 +220,7 @@ async def on_message(self, message: discord.Message) -> None:
217220        resp  =  self .format_embed (links )
218221        await  message .channel .send (embed = resp )
219222
220-     async  def  fetch_data (self , url : str ) ->  tuple [dict [str ], ClientResponse ]:
223+     async  def  fetch_data (self , url : str ) ->  tuple [dict [str ,  Any ], ClientResponse ]:
221224        """Retrieve data as a dictionary and the response in a tuple.""" 
222225        log .trace (f"Querying GH issues API: { url }  )
223226        async  with  self .bot .http_session .get (url , headers = REQUEST_HEADERS ) as  r :
0 commit comments