Skip to content

github_graphql_interface()

A class used to interact with the GitHub GraphQL API. Has a set range of functions.

Source code in github_api_toolkit/__init__.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
class github_graphql_interface():
    """A class used to interact with the GitHub GraphQL API. Has a set range of functions.
    """

    def __init__(self, token: str) -> None:
        self.headers = { "Authorization": "token " + token }
        self.api_url = "https://api.github.com/graphql"

    def get_error_message(self, response: requests.Response) -> tuple:
        """Gets the error message and status code from a response.

        Args:
            response (requests.Response): The response from the API endpoint.

        Returns:
            tuple: A tuple containing the error message and status code.
        """

        response_json = response.json()
        return response_json.get("message", "No Error Message"), response_json.get("status", "Unknown status")

    def make_ql_request(self, query: str, params: dict) -> requests.Response:
        """Makes a request to the GitHub GraphQL API.

        Args:
            query (str): The GraphQL query to be executed.
            params (dict): A dictionary containing the variables for the query.

        Returns:
            requests.Response: The response from the API endpoint.
        """

        self.json = {
            'query': query,
            'variables': params
        }

        return requests.post(url=self.api_url, json=self.json, headers=self.headers)

    def get_domain_email_by_user(self, username: str, org: str) -> list | tuple:
        """Gets a GitHub user's verified domain email for a specific organization.

        Args:
            username (str): The GitHub username of the user.
            org (str): The GitHub organization name.

        Returns:
            list | tuple: A list of verified domain emails for the user in the organization or a tuple containing an error message and status code.
        """

        self.query = '''
            query ($username: String!, $org: String!) {
                user (login: $username) {
                    login
                    organizationVerifiedDomainEmails(login: $org)
                }
            }
        '''

        self.params = {
            'username': username,
            'org': org
        }

        response = self.make_ql_request(self.query, self.params)

        if response.status_code != 200:
            return self.get_error_message(response)

        response_json = response.json()

        if "errors" in response_json:
            return response_json["errors"][0].get("type", "No Error Type"), response_json["errors"][0].get("message", "No Error Message")

        return response.json()["data"]["user"]["organizationVerifiedDomainEmails"]

    def get_file_contents_from_repo(self, owner: str, repo: str, path: str, branch: str = "main") -> str:
        """Gets the contents of a file from a GitHub Repository.

        Args:
            owner (str): The owner of the repository.
            repo (str): The repository name.
            path (str): The path to the file.
            branch (str, optional): The branch the file is on. Defaults to "main".

        Returns:
            str: The contents of the file.
        """

        self.query = f'''
            query ($owner: String!, $repo: String!) {{
                repository(owner: $owner, name: $repo) {{
                    file: object(expression: "{branch}:{path}") {{
                        ... on Blob {{
                            text
                        }}
                    }}
                }}
            }}
        '''

        self.params = {
            'owner': owner,
            'repo': repo
        }

        response = self.make_ql_request(self.query, self.params)

        if response.status_code != 200:
            return self.get_error_message(response)

        try:
            return response.json()["data"]["repository"]["file"]["text"]
        except TypeError:
            # If there is a type error, ["data"]["repository"]["file"] is None
            # Therefore, the file was not found
            return "File not found."

    def check_directory_for_file(self, owner: str, repo: str, path: str, branch: str) -> str | None:
        """Checks if a file exists in a repository.

        Args:
            owner (str): The owner of the repository.
            repo (str): The repository name.
            path (str): The path to the file.
            branch (str): The branch the file is on.

        Returns:
            str | None: The path to the file is found or None if the file is not found.
        """

        response = self.get_file_contents_from_repo(owner, repo, path, branch)

        if response != "File not found.":
            return path

        return

    def locate_codeowners_file(self, owner: str, repo: str, branch: str = "main") -> str | None:
        """Locates the CODEOWNERS file in a repository.

        The CODEOWNERS file can be located in the root of the repository, in the .github/ directory, or in the docs/ directory.

        Args:
            owner (str): The owner of the repository.
            repo (str): The repository name.
            branch (str, optional): The branch the file is on. Defaults to "main".


        Returns:
            str | None: The path to the CODEOWNERS file or None if the file is not found.
        """

        # Check root directory
        response_codeowners = self.check_directory_for_file(owner, repo, "CODEOWNERS", branch)

        # Check .github directory
        response_github = self.check_directory_for_file(owner, repo, ".github/CODEOWNERS", branch)

        # Check docs directory
        response_docs = self.check_directory_for_file(owner, repo, "docs/CODEOWNERS", branch)

        if response_codeowners:
            return response_codeowners
        elif response_github:
            return response_github
        elif response_docs:
            return response_docs

        return

    def get_codeowners_from_text(self, codeowners_content: str) -> list:
        """Gets a list of users and teams from a CODEOWNERS file.

        Args:
            codeowners_content (str): The contents of a CODEOWNERS file.

        Returns:
            list: A list of users and teams from the CODEOWNERS file.
        """

        # Process:
        # 1. Split the CODEOWNERS file into lines.
        # 2. Remove empty lines and comments.
        # 3. Find the index of all instances of @ in the lines.
        # 4. Find the index of when the word after the @ ends (i.e. space, end of line).
        # 5. Get the substring from the @ to the end of the word and add to a list.
        # 6. Remove any emails from the list.
        # 7. Remove duplicates from the list.
        # 8. Return the list.

        codeowner_lines = codeowners_content.split("\n")

        lines_removed = 0

        for i in range(len(codeowner_lines)):
            # If line is empty, remove it

            if codeowner_lines[i-lines_removed] == "":
                codeowner_lines.pop(i-lines_removed)
                lines_removed += 1

            # If whole line is a comment, remove it
            elif codeowner_lines[i-lines_removed][0] == "#":
                codeowner_lines.pop(i-lines_removed)
                lines_removed += 1

            # If line has a comment, remove the comment
            elif "#" in codeowner_lines[i-lines_removed]:
                comment_index = codeowner_lines[i-lines_removed].find("#")
                codeowner_lines[i-lines_removed] = codeowner_lines[i-lines_removed][:comment_index]

        codeowner_handles = []

        for line in codeowner_lines:
            for i in range(len(line)):
                if line[i] == "@":
                    next_space = line.find(" ", i)
                    if next_space == -1:
                        codeowner_handles.append(line[i:])
                    else:
                        codeowner_handles.append(line[i:next_space])

        # The function will grab the end of the emails (i.e. @example.com)
        # These emails need to be removed from the list of codeowner_handles

        email_pattern = r'(@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})'

        lines_removed = 0

        for i in range(len(codeowner_handles)):
            if len(re.findall(email_pattern, codeowner_handles[i-lines_removed])) > 0:
                codeowner_handles.pop(i-lines_removed)
                lines_removed += 1

        # Remove duplicates
        codeowner_handles = list(dict.fromkeys(codeowner_handles))

        return codeowner_handles

    def identify_teams_and_users(self, codeowners_list: list) -> list:
        """Iterates through a list of users and teams and identifies the type of each.

        Args:
            codeowners_list (list): A list of users and teams from a CODEOWNERS file to sort.

        Returns:
            list: A list of dictionaries containing the type and name of each user and team.
        """

        team_and_user_list = []

        for i in range(len(codeowners_list)):
            if "/" in codeowners_list[i]:
                # This is a team
                # Need to remove org from team name

                codeowners_list[i] = codeowners_list[i].split("/")[-1]

                team_and_user_list.append({
                    "type": "team",
                    "name": codeowners_list[i]
                })
            else:
                # This is a user

                codeowners_list[i] = codeowners_list[i].replace("@", "")

                team_and_user_list.append({
                    "type": "user",
                    "name": codeowners_list[i]
                })

        return team_and_user_list

    def get_team_maintainers(self, org: str, team_name: str) -> list | tuple:
        """Gets the maintainers of a GitHub team.

        Args:
            org (str): the GitHub organization name.
            team_name (str): the GitHub team name.

        Returns:
            list | tuple: A list of maintainers in the team or a tuple containing an error message and status code.
        """

        self.query = '''
            query ($org: String!, $team_name: String!) {
                organization(login: $org) {
                    team(slug: $team_name) {
                        members(role: MAINTAINER) {
                            nodes {
                                login
                            }
                        }
                    }
                }
            }
        '''

        self.params = {
            'org': org,
            'team_name': team_name
        }

        response = self.make_ql_request(self.query, self.params)

        if response.status_code != 200:
            return self.get_error_message(response)

        try:
            return response.json()["data"]["organization"]["team"]["members"]["nodes"]
        except TypeError:
            # If there is a type error, ["data"]["organization"]["team"]["members"]["nodes"] is None
            # Therefore, the team was not found
            # Return an empty list
            return []

    def get_codeowner_users(self, org: str, codeowners: list) -> list:
        """Gets a list of users from a list of users and teams. Will get the maintainers of any teams and add them as a user.

        Args:
            org (str): The GitHub organization name.
            codeowners (list): A list of users and teams from a CODEOWNERS file.

        Returns:
            list: A list of users from the CODEOWNERS file.
        """

        users = []

        for codeowner in codeowners:
            if codeowner["type"] == "team":
                team_maintainers = self.get_team_maintainers(org, codeowner["name"])

                for maintainer in team_maintainers:
                    users.append(maintainer["login"])

            elif codeowner["type"] == "user":
                users.append(codeowner["name"])

        # Remove duplicates
        users = list(dict.fromkeys(users))

        return users

    def get_codeowner_emails(self, codeowners: list, org: str) -> list:
        """Gets a list of verified domain emails for a list of users.

        Args:
            codeowners (list): A list of users from a CODEOWNERS file.
            org (str): The GitHub organization to get the email for.

        Returns:
            list: A list of verified domain emails for the users.
        """

        emails = []

        for codeowner in codeowners:
            user_emails = self.get_domain_email_by_user(codeowner, org)

            for email in user_emails:
                emails.append(email)

        return emails

    def get_repository_email_list(self, org: str, repo: str, branch: str = "main") -> list:
        """Gets a list of verified domain emails for the codeowners of a repository.

        Args:
            org (str): The GitHub organization name.
            repo (str): The GitHub repository name.
            branch (str, optional): The branch to check. Defaults to "main".

        Returns:
            list: A list of verified domain emails for the codeowners of the repository.
        """

        codeowners_path = self.locate_codeowners_file(org, repo, branch)

        contents = self.get_file_contents_from_repo(org, repo, codeowners_path)

        codeowners = self.get_codeowners_from_text(contents)

        codeowners = self.identify_teams_and_users(codeowners)

        codeowners = self.get_codeowner_users(org, codeowners)

        emails = self.get_codeowner_emails(codeowners, org)

        return emails

check_directory_for_file(owner, repo, path, branch)

Checks if a file exists in a repository.

Parameters:

Name Type Description Default
owner str

The owner of the repository.

required
repo str

The repository name.

required
path str

The path to the file.

required
branch str

The branch the file is on.

required

Returns:

Type Description
str | None

str | None: The path to the file is found or None if the file is not found.

Source code in github_api_toolkit/__init__.py
def check_directory_for_file(self, owner: str, repo: str, path: str, branch: str) -> str | None:
    """Checks if a file exists in a repository.

    Args:
        owner (str): The owner of the repository.
        repo (str): The repository name.
        path (str): The path to the file.
        branch (str): The branch the file is on.

    Returns:
        str | None: The path to the file is found or None if the file is not found.
    """

    response = self.get_file_contents_from_repo(owner, repo, path, branch)

    if response != "File not found.":
        return path

    return

get_codeowner_emails(codeowners, org)

Gets a list of verified domain emails for a list of users.

Parameters:

Name Type Description Default
codeowners list

A list of users from a CODEOWNERS file.

required
org str

The GitHub organization to get the email for.

required

Returns:

Name Type Description
list list

A list of verified domain emails for the users.

Source code in github_api_toolkit/__init__.py
def get_codeowner_emails(self, codeowners: list, org: str) -> list:
    """Gets a list of verified domain emails for a list of users.

    Args:
        codeowners (list): A list of users from a CODEOWNERS file.
        org (str): The GitHub organization to get the email for.

    Returns:
        list: A list of verified domain emails for the users.
    """

    emails = []

    for codeowner in codeowners:
        user_emails = self.get_domain_email_by_user(codeowner, org)

        for email in user_emails:
            emails.append(email)

    return emails

get_codeowner_users(org, codeowners)

Gets a list of users from a list of users and teams. Will get the maintainers of any teams and add them as a user.

Parameters:

Name Type Description Default
org str

The GitHub organization name.

required
codeowners list

A list of users and teams from a CODEOWNERS file.

required

Returns:

Name Type Description
list list

A list of users from the CODEOWNERS file.

Source code in github_api_toolkit/__init__.py
def get_codeowner_users(self, org: str, codeowners: list) -> list:
    """Gets a list of users from a list of users and teams. Will get the maintainers of any teams and add them as a user.

    Args:
        org (str): The GitHub organization name.
        codeowners (list): A list of users and teams from a CODEOWNERS file.

    Returns:
        list: A list of users from the CODEOWNERS file.
    """

    users = []

    for codeowner in codeowners:
        if codeowner["type"] == "team":
            team_maintainers = self.get_team_maintainers(org, codeowner["name"])

            for maintainer in team_maintainers:
                users.append(maintainer["login"])

        elif codeowner["type"] == "user":
            users.append(codeowner["name"])

    # Remove duplicates
    users = list(dict.fromkeys(users))

    return users

get_codeowners_from_text(codeowners_content)

Gets a list of users and teams from a CODEOWNERS file.

Parameters:

Name Type Description Default
codeowners_content str

The contents of a CODEOWNERS file.

required

Returns:

Name Type Description
list list

A list of users and teams from the CODEOWNERS file.

Source code in github_api_toolkit/__init__.py
def get_codeowners_from_text(self, codeowners_content: str) -> list:
    """Gets a list of users and teams from a CODEOWNERS file.

    Args:
        codeowners_content (str): The contents of a CODEOWNERS file.

    Returns:
        list: A list of users and teams from the CODEOWNERS file.
    """

    # Process:
    # 1. Split the CODEOWNERS file into lines.
    # 2. Remove empty lines and comments.
    # 3. Find the index of all instances of @ in the lines.
    # 4. Find the index of when the word after the @ ends (i.e. space, end of line).
    # 5. Get the substring from the @ to the end of the word and add to a list.
    # 6. Remove any emails from the list.
    # 7. Remove duplicates from the list.
    # 8. Return the list.

    codeowner_lines = codeowners_content.split("\n")

    lines_removed = 0

    for i in range(len(codeowner_lines)):
        # If line is empty, remove it

        if codeowner_lines[i-lines_removed] == "":
            codeowner_lines.pop(i-lines_removed)
            lines_removed += 1

        # If whole line is a comment, remove it
        elif codeowner_lines[i-lines_removed][0] == "#":
            codeowner_lines.pop(i-lines_removed)
            lines_removed += 1

        # If line has a comment, remove the comment
        elif "#" in codeowner_lines[i-lines_removed]:
            comment_index = codeowner_lines[i-lines_removed].find("#")
            codeowner_lines[i-lines_removed] = codeowner_lines[i-lines_removed][:comment_index]

    codeowner_handles = []

    for line in codeowner_lines:
        for i in range(len(line)):
            if line[i] == "@":
                next_space = line.find(" ", i)
                if next_space == -1:
                    codeowner_handles.append(line[i:])
                else:
                    codeowner_handles.append(line[i:next_space])

    # The function will grab the end of the emails (i.e. @example.com)
    # These emails need to be removed from the list of codeowner_handles

    email_pattern = r'(@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})'

    lines_removed = 0

    for i in range(len(codeowner_handles)):
        if len(re.findall(email_pattern, codeowner_handles[i-lines_removed])) > 0:
            codeowner_handles.pop(i-lines_removed)
            lines_removed += 1

    # Remove duplicates
    codeowner_handles = list(dict.fromkeys(codeowner_handles))

    return codeowner_handles

get_domain_email_by_user(username, org)

Gets a GitHub user's verified domain email for a specific organization.

Parameters:

Name Type Description Default
username str

The GitHub username of the user.

required
org str

The GitHub organization name.

required

Returns:

Type Description
list | tuple

list | tuple: A list of verified domain emails for the user in the organization or a tuple containing an error message and status code.

Source code in github_api_toolkit/__init__.py
def get_domain_email_by_user(self, username: str, org: str) -> list | tuple:
    """Gets a GitHub user's verified domain email for a specific organization.

    Args:
        username (str): The GitHub username of the user.
        org (str): The GitHub organization name.

    Returns:
        list | tuple: A list of verified domain emails for the user in the organization or a tuple containing an error message and status code.
    """

    self.query = '''
        query ($username: String!, $org: String!) {
            user (login: $username) {
                login
                organizationVerifiedDomainEmails(login: $org)
            }
        }
    '''

    self.params = {
        'username': username,
        'org': org
    }

    response = self.make_ql_request(self.query, self.params)

    if response.status_code != 200:
        return self.get_error_message(response)

    response_json = response.json()

    if "errors" in response_json:
        return response_json["errors"][0].get("type", "No Error Type"), response_json["errors"][0].get("message", "No Error Message")

    return response.json()["data"]["user"]["organizationVerifiedDomainEmails"]

get_error_message(response)

Gets the error message and status code from a response.

Parameters:

Name Type Description Default
response Response

The response from the API endpoint.

required

Returns:

Name Type Description
tuple tuple

A tuple containing the error message and status code.

Source code in github_api_toolkit/__init__.py
def get_error_message(self, response: requests.Response) -> tuple:
    """Gets the error message and status code from a response.

    Args:
        response (requests.Response): The response from the API endpoint.

    Returns:
        tuple: A tuple containing the error message and status code.
    """

    response_json = response.json()
    return response_json.get("message", "No Error Message"), response_json.get("status", "Unknown status")

get_file_contents_from_repo(owner, repo, path, branch='main')

Gets the contents of a file from a GitHub Repository.

Parameters:

Name Type Description Default
owner str

The owner of the repository.

required
repo str

The repository name.

required
path str

The path to the file.

required
branch str

The branch the file is on. Defaults to "main".

'main'

Returns:

Name Type Description
str str

The contents of the file.

Source code in github_api_toolkit/__init__.py
def get_file_contents_from_repo(self, owner: str, repo: str, path: str, branch: str = "main") -> str:
    """Gets the contents of a file from a GitHub Repository.

    Args:
        owner (str): The owner of the repository.
        repo (str): The repository name.
        path (str): The path to the file.
        branch (str, optional): The branch the file is on. Defaults to "main".

    Returns:
        str: The contents of the file.
    """

    self.query = f'''
        query ($owner: String!, $repo: String!) {{
            repository(owner: $owner, name: $repo) {{
                file: object(expression: "{branch}:{path}") {{
                    ... on Blob {{
                        text
                    }}
                }}
            }}
        }}
    '''

    self.params = {
        'owner': owner,
        'repo': repo
    }

    response = self.make_ql_request(self.query, self.params)

    if response.status_code != 200:
        return self.get_error_message(response)

    try:
        return response.json()["data"]["repository"]["file"]["text"]
    except TypeError:
        # If there is a type error, ["data"]["repository"]["file"] is None
        # Therefore, the file was not found
        return "File not found."

get_repository_email_list(org, repo, branch='main')

Gets a list of verified domain emails for the codeowners of a repository.

Parameters:

Name Type Description Default
org str

The GitHub organization name.

required
repo str

The GitHub repository name.

required
branch str

The branch to check. Defaults to "main".

'main'

Returns:

Name Type Description
list list

A list of verified domain emails for the codeowners of the repository.

Source code in github_api_toolkit/__init__.py
def get_repository_email_list(self, org: str, repo: str, branch: str = "main") -> list:
    """Gets a list of verified domain emails for the codeowners of a repository.

    Args:
        org (str): The GitHub organization name.
        repo (str): The GitHub repository name.
        branch (str, optional): The branch to check. Defaults to "main".

    Returns:
        list: A list of verified domain emails for the codeowners of the repository.
    """

    codeowners_path = self.locate_codeowners_file(org, repo, branch)

    contents = self.get_file_contents_from_repo(org, repo, codeowners_path)

    codeowners = self.get_codeowners_from_text(contents)

    codeowners = self.identify_teams_and_users(codeowners)

    codeowners = self.get_codeowner_users(org, codeowners)

    emails = self.get_codeowner_emails(codeowners, org)

    return emails

get_team_maintainers(org, team_name)

Gets the maintainers of a GitHub team.

Parameters:

Name Type Description Default
org str

the GitHub organization name.

required
team_name str

the GitHub team name.

required

Returns:

Type Description
list | tuple

list | tuple: A list of maintainers in the team or a tuple containing an error message and status code.

Source code in github_api_toolkit/__init__.py
def get_team_maintainers(self, org: str, team_name: str) -> list | tuple:
    """Gets the maintainers of a GitHub team.

    Args:
        org (str): the GitHub organization name.
        team_name (str): the GitHub team name.

    Returns:
        list | tuple: A list of maintainers in the team or a tuple containing an error message and status code.
    """

    self.query = '''
        query ($org: String!, $team_name: String!) {
            organization(login: $org) {
                team(slug: $team_name) {
                    members(role: MAINTAINER) {
                        nodes {
                            login
                        }
                    }
                }
            }
        }
    '''

    self.params = {
        'org': org,
        'team_name': team_name
    }

    response = self.make_ql_request(self.query, self.params)

    if response.status_code != 200:
        return self.get_error_message(response)

    try:
        return response.json()["data"]["organization"]["team"]["members"]["nodes"]
    except TypeError:
        # If there is a type error, ["data"]["organization"]["team"]["members"]["nodes"] is None
        # Therefore, the team was not found
        # Return an empty list
        return []

identify_teams_and_users(codeowners_list)

Iterates through a list of users and teams and identifies the type of each.

Parameters:

Name Type Description Default
codeowners_list list

A list of users and teams from a CODEOWNERS file to sort.

required

Returns:

Name Type Description
list list

A list of dictionaries containing the type and name of each user and team.

Source code in github_api_toolkit/__init__.py
def identify_teams_and_users(self, codeowners_list: list) -> list:
    """Iterates through a list of users and teams and identifies the type of each.

    Args:
        codeowners_list (list): A list of users and teams from a CODEOWNERS file to sort.

    Returns:
        list: A list of dictionaries containing the type and name of each user and team.
    """

    team_and_user_list = []

    for i in range(len(codeowners_list)):
        if "/" in codeowners_list[i]:
            # This is a team
            # Need to remove org from team name

            codeowners_list[i] = codeowners_list[i].split("/")[-1]

            team_and_user_list.append({
                "type": "team",
                "name": codeowners_list[i]
            })
        else:
            # This is a user

            codeowners_list[i] = codeowners_list[i].replace("@", "")

            team_and_user_list.append({
                "type": "user",
                "name": codeowners_list[i]
            })

    return team_and_user_list

locate_codeowners_file(owner, repo, branch='main')

Locates the CODEOWNERS file in a repository.

The CODEOWNERS file can be located in the root of the repository, in the .github/ directory, or in the docs/ directory.

Parameters:

Name Type Description Default
owner str

The owner of the repository.

required
repo str

The repository name.

required
branch str

The branch the file is on. Defaults to "main".

'main'

Returns:

Type Description
str | None

str | None: The path to the CODEOWNERS file or None if the file is not found.

Source code in github_api_toolkit/__init__.py
def locate_codeowners_file(self, owner: str, repo: str, branch: str = "main") -> str | None:
    """Locates the CODEOWNERS file in a repository.

    The CODEOWNERS file can be located in the root of the repository, in the .github/ directory, or in the docs/ directory.

    Args:
        owner (str): The owner of the repository.
        repo (str): The repository name.
        branch (str, optional): The branch the file is on. Defaults to "main".


    Returns:
        str | None: The path to the CODEOWNERS file or None if the file is not found.
    """

    # Check root directory
    response_codeowners = self.check_directory_for_file(owner, repo, "CODEOWNERS", branch)

    # Check .github directory
    response_github = self.check_directory_for_file(owner, repo, ".github/CODEOWNERS", branch)

    # Check docs directory
    response_docs = self.check_directory_for_file(owner, repo, "docs/CODEOWNERS", branch)

    if response_codeowners:
        return response_codeowners
    elif response_github:
        return response_github
    elif response_docs:
        return response_docs

    return

make_ql_request(query, params)

Makes a request to the GitHub GraphQL API.

Parameters:

Name Type Description Default
query str

The GraphQL query to be executed.

required
params dict

A dictionary containing the variables for the query.

required

Returns:

Type Description
Response

requests.Response: The response from the API endpoint.

Source code in github_api_toolkit/__init__.py
def make_ql_request(self, query: str, params: dict) -> requests.Response:
    """Makes a request to the GitHub GraphQL API.

    Args:
        query (str): The GraphQL query to be executed.
        params (dict): A dictionary containing the variables for the query.

    Returns:
        requests.Response: The response from the API endpoint.
    """

    self.json = {
        'query': query,
        'variables': params
    }

    return requests.post(url=self.api_url, json=self.json, headers=self.headers)