Skip to content

Commit 17a1164

Browse files
committed
Add basic checks
1 parent d91c857 commit 17a1164

9 files changed

+147
-10
lines changed

Diff for: checks/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
from checks.base import BaseChecker
22
from checks.repo_not_forked import RepoNotForkedChecker
33
from checks.commit_only_during_hackathon import CommitOnlyDuringHackathonChecker
4+
from checks.only_valid_authors import OnlyValidAuthorsChecker
5+
from checks.substantial_authors_contributions import SubstantialAuthorsContributionsChecker
6+
# from checks.source_code_not_similar_to_other_user_project import SourceCodeSimilarityChecker
7+
# from checks.no_commit_overlap_with_other_user_project import NoCommitOverlapWithOtherUserProjectChecker

Diff for: checks/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from abc import ABCMeta, abstractmethod
2-
from datatypes import Submission, HackathonConfig
2+
from datatypes import Submission, HackathonConfig, RepoInfo
33
from typing import Tuple, Optional
44

55

66
class BaseChecker(metaclass=ABCMeta):
77
@staticmethod
88
@abstractmethod
9-
def perform_check(submission: Submission, config: HackathonConfig) -> Tuple[bool, Optional[str]]:
9+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
1010
raise NotImplementedError
1111

1212
@property

Diff for: checks/commit_only_during_hackathon.py

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
11
from checks.base import BaseChecker
2-
from datatypes import Submission, HackathonConfig
2+
from datatypes import Submission, HackathonConfig, RepoInfo
33
from typing import Tuple, Optional
44

55

66
class CommitOnlyDuringHackathonChecker(BaseChecker):
77
check_name = "commit_only_during_hackathon"
88

99
@staticmethod
10-
def perform_check(submission: Submission, config: HackathonConfig) -> Tuple[bool, Optional[str]]:
11-
# TODO Implement check method
12-
return True, "Committed only during hackathon"
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
11+
sorted_commits = sorted(repo_info.commits, key=lambda c: c.last_modified_datetime)
12+
last_commit_before_hackathon_started, first_commit_after_hackathon_ended = None, None
13+
14+
for commit in sorted_commits:
15+
if commit.last_modified_datetime < config.start_at:
16+
last_commit_before_hackathon_started = commit
17+
18+
if commit.last_modified_datetime > config.end_at:
19+
first_commit_after_hackathon_ended = commit
20+
break
21+
22+
if not last_commit_before_hackathon_started and not first_commit_after_hackathon_ended:
23+
return True, None
24+
25+
remarks = ""
26+
27+
if last_commit_before_hackathon_started is not None:
28+
remarks += f"The last commit before the hackathon is {last_commit_before_hackathon_started.html_url}\n"
29+
30+
if first_commit_after_hackathon_ended is not None:
31+
remarks += f"The first commit after the hackathon is {first_commit_after_hackathon_ended.html_url}"
32+
33+
return False, remarks

Diff for: checks/no_commit_overlap_with_other_user_project.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from checks.base import BaseChecker
2+
from datatypes import Submission, HackathonConfig, RepoInfo
3+
from typing import Tuple, Optional
4+
5+
6+
class NoCommitOverlapWithOtherUserProjectChecker(BaseChecker):
7+
check_name = "no_commit_overlap_with_other_user_project"
8+
9+
@staticmethod
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[
11+
bool, Optional[str]]:
12+
# TODO Implement check method
13+
return True, "No commit overlap with other projects found"

Diff for: checks/only_valid_authors.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from checks.base import BaseChecker
2+
from datatypes import Submission, HackathonConfig, RepoInfo
3+
from typing import Tuple, Optional
4+
5+
6+
class OnlyValidAuthorsChecker(BaseChecker):
7+
check_name = "only_valid_authors"
8+
9+
@staticmethod
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
11+
contributors = {commit.author.login for commit in repo_info.commits}
12+
expected_contributors = set(submission.authors)
13+
14+
if contributors == expected_contributors:
15+
return True, None
16+
elif contributors.issubset(expected_contributors):
17+
people_who_didnt_contribute = ", ".join(expected_contributors - contributors)
18+
return True, f"{people_who_didnt_contribute} did not commit anything"
19+
else:
20+
expected_contributors_names = ", ".join(expected_contributors)
21+
actual_contributors_names = ", ".join(contributors)
22+
return False, f"Expected {expected_contributors_names} to author commits but instead {actual_contributors_names} did"

Diff for: checks/repo_not_forked.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from checks.base import BaseChecker
2-
from datatypes import Submission, HackathonConfig
2+
from datatypes import Submission, HackathonConfig, RepoInfo
33
from typing import Tuple, Optional
44

55

66
class RepoNotForkedChecker(BaseChecker):
77
check_name = "repo_not_forked"
88

99
@staticmethod
10-
def perform_check(submission: Submission, config: HackathonConfig) -> Tuple[bool, Optional[str]]:
11-
# TODO Implement check method
12-
return True, "We won"
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
11+
if not repo_info.repo.parent:
12+
return True, None
13+
14+
return False, f"Project was forked from {repo_info.repo.parent}"
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from checks.base import BaseChecker
2+
from datatypes import Submission, HackathonConfig, RepoInfo
3+
from typing import Tuple, Optional
4+
5+
6+
class SourceCodeSimilarityChecker(BaseChecker):
7+
check_name = "source_code_not_similar_to_other_user_project"
8+
9+
@staticmethod
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
11+
# TODO Implement check method
12+
return True, "Not Similar"

Diff for: checks/substantial_authors_contributions.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from checks.base import BaseChecker
2+
from datatypes import Submission, HackathonConfig, RepoInfo
3+
from typing import Tuple, Optional
4+
5+
6+
class SubstantialAuthorsContributionsChecker(BaseChecker):
7+
check_name = "substantial_authors_contributions"
8+
9+
@staticmethod
10+
def perform_check(submission: Submission, config: HackathonConfig, repo_info: RepoInfo) -> Tuple[bool, Optional[str]]:
11+
num_commits = len(repo_info.commits)
12+
13+
if num_commits > 5:
14+
return True, None
15+
16+
return False, f"This project only has {num_commits} commits"

Diff for: checks/utils.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from github import Github
2+
from datatypes import RepoInfo
3+
from typing import Optional
4+
from datetime import datetime
5+
from pytz import UTC
6+
import os
7+
8+
9+
# GitHub Related Utils
10+
def get_github() -> Github:
11+
return Github(os.getenv("GITHUB_ACCESS_TOKEN"))
12+
13+
14+
def get_user(github_username):
15+
try:
16+
usr = get_github().get_user(github_username)
17+
except Exception as e:
18+
return None
19+
20+
21+
def get_repo_id(repo_url):
22+
if repo_url.endswith('.git'):
23+
repo_url = repo_url[:-4]
24+
return repo_url.rstrip('/').split("github.com/")[1]
25+
26+
27+
def parse_commit_datetime(datetime_str) -> datetime:
28+
format = "%Y-%m-%dT%H:%M:%SZ"
29+
alternate_format = "%a, %d %b %Y %H:%M:%S %Z"
30+
return UTC.localize(datetime.strptime(datetime_str, format))
31+
32+
33+
def get_repo_info(repo_url) -> Optional[RepoInfo]:
34+
repo_id = get_repo_id(repo_url)
35+
try:
36+
repo = get_github().get_repo(repo_id)
37+
commits = list(repo.get_commits())
38+
39+
for commit in commits:
40+
datetime_str = commit.raw_data['commit']['author']['date']
41+
commit.last_modified_datetime = parse_commit_datetime(datetime_str)
42+
43+
return RepoInfo(repo, commits)
44+
45+
except Exception as e:
46+
print(e)
47+
return None

0 commit comments

Comments
 (0)