def test_github_example_matches( path: str, expected: List[Tuple[Literal["USERNAME", "EMAIL", "TEAM"], str]]) -> None: owners = CodeOwners(EXAMPLE) actual = owners.of(path) assert (actual == expected ), f"mismatch for {path}, expected: {expected}, got: {actual}"
def test_specific_pattern_path_matching(name: str, pattern: str, paths: Dict[str, bool]) -> None: assert paths for path, expected in paths.items(): owners = CodeOwners(f"{pattern} @js-user") matches = owners.of(path) == [("USERNAME", "@js-user")] regex, *_ = owners.paths[0] assert ( matches == expected ), f"""{pattern} {regex} {"matches" if expected else "shouldn't match"} {path}"""
def test_codeowners(pattern, expected): # for some reason the codeowners library does not publish all the wheels # for Mac and Windows. Eventually we could write our own codeowners parser, # but for now it is good enough. If codeowners is not installed, this test # will be skipped try: from codeowners import CodeOwners except: pytest.skip("Skipping as codeowners not installed.") with open(".github/CODEOWNERS") as f: owners = CodeOwners(f.read()) assert set(owners.of(pattern)) == expected
async def conclude_reviewer_list(owner: str = None, repo: str = None) -> typing.List[str]: """Conclude on a set of Reviewers (their GitHub user id) that could be assigned to a Pull Request.""" reviewers = [] github_api = None if owner is None or repo is None: return None try: github_api = RUNTIME_CONTEXT.app_installation_client except Exception: access_token = GitHubOAuthToken(os.environ["GITHUB_ACCESS_TOKEN"]) github_api = RawGitHubAPI(access_token, user_agent="sesheta-actions") try: codeowners = await github_api.getitem( f"/repos/{owner}/{repo}/contents/.github/CODEOWNERS") codeowners_content = base64.b64decode( codeowners["content"]).decode("utf-8") code_owner = CodeOwners(codeowners_content) for owner in code_owner.of("."): reviewers.append(owner[1][1:]) # remove the @ except gidgethub.HTTPException as http_exception: # if there is no CODEOWNERS, lets have some sane defaults if http_exception.status_code == 404: if owner.lower() == "thoth-station": reviewers.append("fridex") reviewers.append("pacospace") if "prometheus" in repo.lower(): reviewers.append("4n4nd") reviewers.append("MichaelClifford") if "log-" in repo.lower(): reviewers.append("zmhassan") reviewers.append("4n4nd") else: _LOGGER.error(http_exception) return None except Exception as err: # on any other Error, we can not generate a reviewers list _LOGGER.error(str(err)) return None _LOGGER.debug(f"final reviewers: '{reviewers}'") return reviewers
def main(): app_id = os.getenv('GITHUB_APP_ID') private_key = os.getenv('GITHUB_PRIVATE_KEY').encode('utf-8') organization_name, repository_name = os.getenv('PROJECT').split('/') pull_request_id = os.getenv('PULL_REQUEST_ID') github_app = github.GitHub() github_app.login_as_app(private_key, app_id) app_slug = github_app.authenticated_app().slug github_installation = github.GitHub() github_installation.login_as_app_installation( private_key, app_id, github_app.app_installation_for_repository(organization_name, repository_name).id) organization = github_installation.organization(organization_name) repository = github_installation.repository(organization.login, repository_name) pull_request = github_installation.pull_request(organization.login, repository.name, pull_request_id) # Get reviewers reviewers = set() try: owner_file_contents = repository.file_contents('CODEOWNERS') data = owner_file_contents.decoded.decode('utf-8') code_owners = CodeOwners(data) for f in pull_request.files(): file_reviewers = code_owners.of(f.filename) if file_reviewers is None: continue for reviewer_type, reviewer in file_reviewers: if reviewer_type == 'USERNAME': reviewers.add(reviewer.replace('@', '')) continue raise SystemError("Unknown reviewer_type: %s" % reviewer_type) except: return 0 # Get last commit date commit_dates = [] for c in pull_request.commits(): date = dateutil_parser.parse(c.commit.committer['date']) commit_dates.append(date) last_commit_date = max(commit_dates) if commit_dates else None # Parse comments approvals = set() for comment in pull_request.issue_comments(): # Find the signoffs if comment.created_at > last_commit_date: for line in comment.body.split("\n"): if line.strip() in APPROVAL_ALIASES: approvals.add(comment.user.login) if any([(r in approvals) for r in reviewers]): pull_request.create_review("Pull Request Approved.", list(pull_request.commits())[-1].sha, 'APPROVE') return 0 return 1