Skip to content

Commit beea051

Browse files
authored
Add files via upload
1 parent 5a96260 commit beea051

File tree

1 file changed

+282
-92
lines changed

1 file changed

+282
-92
lines changed

main.py

Lines changed: 282 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,282 @@
1-
import argparse
2-
from datetime import datetime
3-
import pytz
4-
5-
import git_logger
6-
import export_sheets
7-
import commits_parser
8-
import pull_requests_parser
9-
import issues_parser
10-
import invites_parser
11-
import wikipars
12-
13-
def parse_args():
14-
parser = argparse.ArgumentParser()
15-
parser.add_argument("--invites", help="print pending invites", action="store_true")
16-
parser.add_argument("-c", "--commits", help="log commits", action="store_true")
17-
parser.add_argument("-p", "--pull_requests", help="log pull requests", action="store_true")
18-
parser.add_argument("-i", "--issues", help="log issues", action="store_true")
19-
parser.add_argument("-w", "--wikis", help="log wikis", action="store_true")
20-
parser.add_argument("--forks_include", help="logging data from forks", action="store_true")
21-
parser.add_argument("-e", "--export_google_sheets", help="export table to google sheets", action="store_true")
22-
parser.add_argument('-t', '--token', type=str, required=True, help='token github account')
23-
parser.add_argument('-l', '--list', type=str, required=True, help='Path to the file containing the list of repositories. Repositories should be separated by a line break. Names should be in the format <organization or owner>/<name> ')
24-
parser.add_argument("--download_repos", type=str, help="path to downloaded repositories", default='./')
25-
parser.add_argument('-o', '--out', type=str, required=True, help='output filename')
26-
parser.add_argument("--pr_comments", help="log comments for PR", action="store_true")
27-
parser.add_argument('-s', '--start', type=str, required=False, help='start time', default='2000/01/01-00:00:00')
28-
parser.add_argument('-f', '--finish', type=str, required=False, help='finish time', default='2400/01/01-00:00:00')
29-
parser.add_argument('-b', '--branch', type=str, required=False, help='branch to select commits, by default use "default" repository branch, use "all" to get all commits from all branches', default=None)
30-
parser.add_argument('--google_token', type=str, required=False, help='Specify path to google token file')
31-
parser.add_argument('--table_id', type=str, required=False,
32-
help='Specify Google sheet document id (can find in url)')
33-
parser.add_argument('--sheet_id', type=str, required=False,
34-
help='Specify title for a sheet in a document in which data will be printed')
35-
args = parser.parse_args()
36-
37-
if args.export_google_sheets:
38-
for action in parser._actions:
39-
if action.dest == 'google_token':
40-
action.required = True
41-
if action.dest == 'table_id':
42-
action.required = True
43-
if action.dest == 'sheet_id':
44-
action.required = True
45-
return parser.parse_args()
46-
47-
48-
def parse_time(datetime_str):
49-
start = datetime_str[0].split('/') + datetime_str[1].split(':') if len(datetime_str) == 2 \
50-
else datetime_str[0].split('/') + ['00', '00', '00']
51-
start = [int(i) for i in start]
52-
start_datetime = datetime(year=start[0], month=start[1], day=start[2], hour=start[3], minute=start[4],
53-
second=start[5])
54-
return start_datetime.astimezone(pytz.timezone(git_logger.TIMEZONE))
55-
56-
57-
def main():
58-
args = parse_args()
59-
token = args.token
60-
repositories = args.list
61-
csv_name = args.out
62-
path_drepo = args.download_repos
63-
fork_flag = args.forks_include
64-
log_pr_comments = args.pr_comments
65-
start, finish = None, None
66-
67-
try:
68-
client = git_logger.login(token=token)
69-
except Exception as e:
70-
print(e)
71-
else:
72-
working_repos = git_logger.get_next_repo(client, repositories)
73-
if args.start:
74-
start = parse_time(args.start.split('-'))
75-
if args.finish:
76-
finish = parse_time(args.finish.split('-'))
77-
if args.commits:
78-
commits_parser.log_commits(client, working_repos, csv_name, start, finish, args.branch, fork_flag)
79-
if args.pull_requests:
80-
pull_requests_parser.log_pull_requests(client, working_repos, csv_name, token, start, finish, fork_flag, log_pr_comments)
81-
if args.issues:
82-
issues_parser.log_issues(client, working_repos, csv_name, token, start, finish, fork_flag)
83-
if args.invites:
84-
invites_parser.log_invitations(client, working_repos, csv_name)
85-
if args.wikis:
86-
wikipars.wikiparser(client, repositories, path_drepo, csv_name)
87-
if args.export_google_sheets:
88-
export_sheets.write_data_to_table(csv_name, args.google_token, args.table_id, args.sheet_id)
89-
90-
91-
if __name__ == '__main__':
92-
main()
1+
from abc import ABC, abstractmethod
2+
from datetime import datetime
3+
from typing import List, Dict, Optional
4+
import logging
5+
6+
# Настройка логирования
7+
logging.basicConfig(
8+
level=logging.INFO,
9+
format="%(asctime)s - %(levelname)s - %(message)s"
10+
)
11+
12+
# Модельные классы
13+
class Repository:
14+
def __init__(self, id: str, name: str, url: str):
15+
self.id = id
16+
self.name = name
17+
self.url = url
18+
19+
def __repr__(self):
20+
return f"Repository(id={self.id}, name={self.name}, url={self.url})"
21+
22+
class Commit:
23+
def __init__(self, id: str, message: str, author: 'Contributor', date: datetime):
24+
self.id = id
25+
self.message = message
26+
self.author = author
27+
self.date = date
28+
29+
def __repr__(self):
30+
return f"Commit(id={self.id}, message={self.message}, author={self.author}, date={self.date})"
31+
32+
class Contributor:
33+
def __init__(self, username: str, email: str):
34+
self.username = username
35+
self.email = email
36+
37+
def __repr__(self):
38+
return f"Contributor(username={self.username}, email={self.email})"
39+
40+
class Issue:
41+
def __init__(self, id: str, title: str, author: Contributor, state: str):
42+
self.id = id
43+
self.title = title
44+
self.author = author
45+
self.state = state
46+
47+
def __repr__(self):
48+
return f"Issue(id={self.id}, title={self.title}, author={self.author}, state={self.state})"
49+
50+
class PullRequest:
51+
def __init__(self, id: str, title: str, author: Contributor, state: str):
52+
self.id = id
53+
self.title = title
54+
self.author = author
55+
self.state = state
56+
57+
def __repr__(self):
58+
return f"PullRequest(id={self.id}, title={self.title}, author={self.author}, state={self.state})"
59+
60+
class WikiPage:
61+
def __init__(self, title: str, content: str):
62+
self.title = title
63+
self.content = content
64+
65+
def __repr__(self):
66+
return f"WikiPage(title={self.title}, content={self.content[:50]}...)" # Ограничиваем вывод content для удобства
67+
68+
# Интерфейс API
69+
class IRepositoryAPI(ABC):
70+
@abstractmethod
71+
def get_repository(self, id: str) -> Optional[Repository]:
72+
"""Получить репозиторий по его идентификатору."""
73+
pass
74+
75+
@abstractmethod
76+
def get_commits(self, repo: Repository) -> List[Commit]:
77+
"""Получить список коммитов для репозитория."""
78+
pass
79+
80+
@abstractmethod
81+
def get_contributors(self, repo: Repository) -> List[Contributor]:
82+
"""Получить список контрибьюторов для репозитория."""
83+
pass
84+
85+
@abstractmethod
86+
def get_issues(self, repo: Repository) -> List[Issue]:
87+
"""Получить список issues для репозитория."""
88+
pass
89+
90+
@abstractmethod
91+
def get_pull_requests(self, repo: Repository) -> List[PullRequest]:
92+
"""Получить список pull requests для репозитория."""
93+
pass
94+
95+
@abstractmethod
96+
def get_wiki_pages(self, repo: Repository) -> List[WikiPage]:
97+
"""Получить список wiki-страниц для репозитория."""
98+
pass
99+
100+
# Реализация для GitHub
101+
class GitHubRepoAPI(IRepositoryAPI):
102+
def __init__(self, client):
103+
self.client = client
104+
105+
def get_repository(self, id: str) -> Optional[Repository]:
106+
try:
107+
repo = self.client.get_repo(id)
108+
return Repository(repo.full_name, repo.name, repo.html_url)
109+
except Exception as e:
110+
logging.error(f"Failed to get repository {id} from GitHub: {e}")
111+
return None
112+
113+
def get_commits(self, repo: Repository) -> List[Commit]:
114+
try:
115+
commits = self.client.get_repo(repo.id).get_commits()
116+
return [
117+
Commit(
118+
c.sha,
119+
c.commit.message,
120+
Contributor(c.author.login if c.author else "unknown", c.commit.author.email),
121+
c.commit.author.date
122+
) for c in commits
123+
]
124+
except Exception as e:
125+
logging.error(f"Failed to get commits from GitHub for repo {repo.name}: {e}")
126+
return []
127+
128+
def get_contributors(self, repo: Repository) -> List[Contributor]:
129+
try:
130+
contributors = self.client.get_repo(repo.id).get_contributors()
131+
return [Contributor(c.login, c.email or "") for c in contributors]
132+
except Exception as e:
133+
logging.error(f"Failed to get contributors from GitHub for repo {repo.name}: {e}")
134+
return []
135+
136+
def get_issues(self, repo: Repository) -> List[Issue]:
137+
try:
138+
issues = self.client.get_repo(repo.id).get_issues(state='all')
139+
return [
140+
Issue(
141+
i.number,
142+
i.title,
143+
Contributor(i.user.login, i.user.email or ""),
144+
i.state
145+
) for i in issues
146+
]
147+
except Exception as e:
148+
logging.error(f"Failed to get issues from GitHub for repo {repo.name}: {e}")
149+
return []
150+
151+
def get_pull_requests(self, repo: Repository) -> List[PullRequest]:
152+
try:
153+
pulls = self.client.get_repo(repo.id).get_pulls(state='all')
154+
return [
155+
PullRequest(
156+
p.number,
157+
p.title,
158+
Contributor(p.user.login, p.user.email or ""),
159+
p.state
160+
) for p in pulls
161+
]
162+
except Exception as e:
163+
logging.error(f"Failed to get pull requests from GitHub for repo {repo.name}: {e}")
164+
return []
165+
166+
def get_wiki_pages(self, repo: Repository) -> List[WikiPage]:
167+
# GitHub API не поддерживает прямое получение wiki-страниц
168+
return []
169+
170+
# Реализация для Forgejo
171+
class ForgejoRepoAPI(IRepositoryAPI):
172+
def __init__(self, client):
173+
self.client = client
174+
175+
def get_repository(self, id: str) -> Optional[Repository]:
176+
try:
177+
owner, repo_name = id.split('/')
178+
repo = self.client.repo_get(owner, repo_name)
179+
return Repository(repo['id'], repo['name'], repo['html_url'])
180+
except Exception as e:
181+
logging.error(f"Failed to get repository {id} from Forgejo: {e}")
182+
return None
183+
184+
def get_commits(self, repo: Repository) -> List[Commit]:
185+
try:
186+
owner, repo_name = repo.id.split('/')
187+
commits = self.client.repo_list_commits(owner, repo_name)
188+
return [
189+
Commit(
190+
c['sha'],
191+
c['message'],
192+
Contributor(c['author']['username'], c['author']['email']),
193+
datetime.fromisoformat(c['date'])
194+
) for c in commits
195+
]
196+
except Exception as e:
197+
logging.error(f"Failed to get commits from Forgejo for repo {repo.name}: {e}")
198+
return []
199+
200+
def get_contributors(self, repo: Repository) -> List[Contributor]:
201+
try:
202+
owner, repo_name = repo.id.split('/')
203+
contributors = self.client.repo_list_contributors(owner, repo_name)
204+
return [Contributor(c['username'], c['email']) for c in contributors]
205+
except Exception as e:
206+
logging.error(f"Failed to get contributors from Forgejo for repo {repo.name}: {e}")
207+
return []
208+
209+
def get_issues(self, repo: Repository) -> List[Issue]:
210+
try:
211+
owner, repo_name = repo.id.split('/')
212+
issues = self.client.repo_list_issues(owner, repo_name)
213+
return [
214+
Issue(
215+
i['number'],
216+
i['title'],
217+
Contributor(i['user']['username'], i['user']['email']),
218+
i['state']
219+
) for i in issues
220+
]
221+
except Exception as e:
222+
logging.error(f"Failed to get issues from Forgejo for repo {repo.name}: {e}")
223+
return []
224+
225+
def get_pull_requests(self, repo: Repository) -> List[PullRequest]:
226+
try:
227+
owner, repo_name = repo.id.split('/')
228+
pulls = self.client.repo_list_pull_requests(owner, repo_name)
229+
return [
230+
PullRequest(
231+
p['number'],
232+
p['title'],
233+
Contributor(p['user']['username'], p['user']['email']),
234+
p['state']
235+
) for p in pulls
236+
]
237+
except Exception as e:
238+
logging.error(f"Failed to get pull requests from Forgejo for repo {repo.name}: {e}")
239+
return []
240+
241+
def get_wiki_pages(self, repo: Repository) -> List[WikiPage]:
242+
try:
243+
owner, repo_name = repo.id.split('/')
244+
wiki_pages = self.client.repo_list_wiki_pages(owner, repo_name)
245+
return [WikiPage(page['title'], page['content']) for page in wiki_pages]
246+
except Exception as e:
247+
logging.error(f"Failed to get wiki pages from Forgejo for repo {repo.name}: {e}")
248+
return []
249+
250+
# Фабрика для создания API
251+
class RepositoryFactory:
252+
@staticmethod
253+
def create_api(source: str, client) -> IRepositoryAPI:
254+
if client is None:
255+
raise ValueError("Client cannot be None")
256+
if source == 'github':
257+
return GitHubRepoAPI(client)
258+
elif source == 'forgejo':
259+
return ForgejoRepoAPI(client)
260+
else:
261+
raise ValueError(f"Unsupported source: {source}")
262+
263+
# Сервис для расчёта метрик
264+
class CommitmentCalculator:
265+
def __init__(self, api: IRepositoryAPI):
266+
self.api = api
267+
268+
def calculate(self, repo: Repository) -> Dict[str, int]:
269+
if not repo:
270+
return {}
271+
try:
272+
commits = self.api.get_commits(repo)
273+
if not commits:
274+
return {}
275+
result = {}
276+
for commit in commits:
277+
author = commit.author.username
278+
result[author] = result.get(author, 0) + 1
279+
return result
280+
except Exception as e:
281+
logging.error(f"Failed to calculate commitment for repo {repo.name}: {e}")
282+
return {}

0 commit comments

Comments
 (0)