Skip to content

Commit d416547

Browse files
authored
multiple-tokens support implemented (#89)
1 parent 96c709a commit d416547

File tree

8 files changed

+104
-46
lines changed

8 files changed

+104
-46
lines changed

README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,28 @@ docker run -v $(pwd)/output:/app/output checking_repo [--invites] [--commites] [
2424
## Запуск приложения:
2525
1. Логирование commits
2626
```commandline
27-
python3 main.py [-c, --commits] [-t, --token] token (github токен вместо token) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [-b, --branch] branch (branch - название конкретной ветки, откуда брать коммиты или all - логгировать все коммиты изо всех веток)
27+
python3 main.py [-c, --commits] (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [-b, --branch] branch (branch - название конкретной ветки, откуда брать коммиты или all - логгировать все коммиты изо всех веток)
2828
```
2929
2. Логирование issues
3030
```commandline
31-
python3 main.py [-i, --issues] [-t, --token] token (github токен вместо token) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
31+
python3 main.py [-i, --issues] (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
3232
```
3333
3. Логирование pull requests
3434
```commandline
35-
python3 main.py [-p, --pull_requests] [-t, --token] token (github токен вместо token) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [--pr_comments] (если установлен - также выгружаются комментарии к PR)
35+
python3 main.py [-p, --pull_requests] (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [--pr_comments] (если установлен - также выгружаются комментарии к PR)
3636
```
3737
4. Логирование непринятых приглашений в репо
3838
```commandline
39-
python3 main.py --invites [-t, --token] token (github токен вместо token) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
39+
python3 main.py --invites (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
4040
```
4141
5. Логирование вики-репозиториев
4242
```commandline
43-
python3 main.py [-w, --wikis] [-t, --token] token (github токен вместо token) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) --dowland_repos path_drepo (path_drepo - строка пути к директории, где сохраняются вики-репозитории) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
43+
python3 main.py [-w, --wikis] (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) --dowland_repos path_drepo (path_drepo - строка пути к директории, где сохраняются вики-репозитории) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
44+
```
45+
6. Логирование контрибьюторов
46+
```commandline
47+
python3 main.py --contributors (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) --dowland_repos path_drepo (path_drepo - строка пути к директории, где сохраняются вики-репозитории) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
4448
```
45-
4649

4750

4851
## Получение токена для работы с Google таблицей:
@@ -60,10 +63,15 @@ python3 main.py [-w, --wikis] [-t, --token] token (github токен вмест
6063
## Экспорт таблицы в Google Sheets:
6164

6265
``` commandline
63-
python3 main.py [-p, --pull_requests] [-t, --token] token (github токен вместо token) [-l,--list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [--google_token] token.json (файл с google токеном) [--table_id] table_id (id таблицы, указанной в url пути до таблицы) [--sheet_id] sheet_id (id конкретного листа в таблице google)
66+
python3 main.py [-p, --pull_requests] (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l,--list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи) [--google_token] token.json (файл с google токеном) [--table_id] table_id (id таблицы, указанной в url пути до таблицы) [--sheet_id] sheet_id (id конкретного листа в таблице google)
6467
```
6568

6669
## Файл со списком репозиториев:
6770

6871
Репозитории хранятся в txt файле. Каждый репозиторий записывается в отдельную строку.
6972
Должно быть указано полное имя репозитория. (Название организации/название репозитория)
73+
74+
## Файл со списком токенов:
75+
76+
Каждый токен записывается в отдельную строку.
77+
Токены должны быть привзязаны к разным github аккаунтам. Токены, привязанные к одному аккаунту имеют общий rate_limit.

commits_parser.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,10 @@ def log_repository_commits(repository: Repository, csv_name, start, finish, bran
5959
sleep(TIMEDELTA)
6060

6161

62-
def log_commits(
63-
client: Github, working_repos, csv_name, start, finish, branch, fork_flag
64-
):
62+
def log_commits(working_repos, csv_name, start, finish, branch, fork_flag):
6563
logger.log_to_csv(csv_name, FIELDNAMES)
6664

67-
for repo in working_repos:
65+
for repo, token in working_repos:
6866
try:
6967
logger.log_title(repo.full_name)
7068
log_repository_commits(repo, csv_name, start, finish, branch)

contributors_parser.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,10 @@ def get_contributors_stats(repository: Repository) -> dict:
7272
return contributors_stats
7373

7474

75-
def log_contributors(
76-
client: Github, working_repos: Generator, csv_name: str, fork_flag: bool
77-
):
75+
def log_contributors(working_repos: Generator, csv_name: str, fork_flag: bool):
7876
logger.log_to_csv(csv_name, FIELDNAMES)
7977

80-
for repo in working_repos:
78+
for repo, token in working_repos:
8179
try:
8280
logger.log_title(repo.full_name)
8381
log_repository_contributors(repo, csv_name)

git_logger.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,63 @@ def login(token):
1818
return client
1919

2020

21-
def get_next_repo(client: Github, repositories):
21+
def get_tokens_from_file(tokens_path: str) -> list[str]:
22+
with open(tokens_path, 'r') as file:
23+
tokens = [token for token in file.read().split('\n') if token]
24+
25+
return tokens
26+
27+
28+
class GithubClients:
29+
def __init__(self, tokens: list[str]):
30+
self.clients = self._init_clients(tokens)
31+
self.cur_client = None
32+
33+
def _init_clients(self, tokens: list[str]) -> list[dict]:
34+
clients = [{"client": login(token), "token": token} for token in tokens]
35+
# нужно ли нам рейзить ошибку в случае 403, или просто временно пропускать эти токены?
36+
37+
return clients
38+
39+
def get_next_client(self) -> Github:
40+
client = None
41+
max_remaining_limit = -1
42+
43+
for client_tmp in self.clients:
44+
remaining_limit, limit = client_tmp["client"].rate_limiting
45+
46+
# можно добавить вывод износа токена
47+
# можно дополнительно проверять на 403 и временно пропускать эти токены,
48+
# либо завести константу "минимальный коэффициент износа" и не трогать "изношенные" токены
49+
50+
if remaining_limit > max_remaining_limit:
51+
client = client_tmp
52+
max_remaining_limit = remaining_limit
53+
54+
sleep(TIMEDELTA)
55+
56+
if client is None:
57+
raise Exception("No github-clients available")
58+
59+
self.cur_client = client
60+
return client
61+
62+
63+
def get_next_repo(clients: GithubClients, repositories):
2264
with open(repositories, 'r') as file:
2365
list_repos = [x for x in file.read().split('\n') if x]
2466
print(list_repos)
2567
for repo_name in list_repos:
2668
try:
27-
repo = client.get_repo(repo_name)
69+
cur_client = clients.get_next_client()
70+
repo = cur_client['client'].get_repo(repo_name)
2871
except GithubException as err:
2972
print(f'Github: Connect: error {err.data}')
3073
print(f'Github: Connect: failed to load repository "{repo_name}"')
3174
exit(1)
3275
else:
33-
yield repo
76+
print(cur_client['token'])
77+
yield repo, cur_client['token']
3478

3579

3680
def get_assignee_story(github_object):

invites_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ def log_repository_invitations(repository: Repository, csv_name):
3636
sleep(TIMEDELTA)
3737

3838

39-
def log_invitations(client: Github, working_repos, csv_name):
39+
def log_invitations(working_repos, csv_name):
4040
logger.log_to_csv(csv_name, FIELDNAMES)
4141

42-
for repo in working_repos:
42+
for repo, token in working_repos:
4343
logger.log_title(repo.full_name)
4444
try:
4545
log_repository_invitations(repo, csv_name)

issues_parser.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import requests
44
import json
55
from time import sleep
6-
from git_logger import get_assignee_story
6+
from git_logger import get_assignee_story, GithubClients
77
from github import Github, Repository, GithubException, PullRequest
88

99
EMPTY_FIELD = 'Empty field'
@@ -172,17 +172,23 @@ def log_repository_issues(repository: Repository, csv_name, token, start, finish
172172
sleep(TIMEDELTA)
173173

174174

175-
def log_issues(client: Github, working_repo, csv_name, token, start, finish, fork_flag):
175+
def log_issues(working_repo, csv_name, start, finish, fork_flag):
176176
logger.log_to_csv(csv_name, FIELDNAMES)
177177

178-
for repo in working_repo:
178+
for repo, token in working_repo:
179179
try:
180180
logger.log_title(repo.full_name)
181181
log_repository_issues(repo, csv_name, token, start, finish)
182182
if fork_flag:
183183
for forked_repo in repo.get_forks():
184184
logger.log_title("FORKED:", forked_repo.full_name)
185-
log_repository_issues(forked_repo, csv_name, token, start, finish)
185+
log_repository_issues(
186+
forked_repo,
187+
csv_name,
188+
token,
189+
start,
190+
finish,
191+
)
186192
sleep(TIMEDELTA)
187193
sleep(TIMEDELTA)
188194
except Exception as e:

main.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ def parse_args():
3131
help="export table to google sheets",
3232
action="store_true",
3333
)
34-
parser.add_argument(
35-
'-t', '--token', type=str, required=True, help='token github account'
36-
)
34+
35+
token = parser.add_mutually_exclusive_group(required=True)
36+
token.add_argument('-t', '--token', type=str, help='token github account')
37+
token.add_argument('--tokens', type=str, help='path to your tokens')
38+
3739
parser.add_argument(
3840
'-l',
3941
'--list',
@@ -126,49 +128,48 @@ def parse_time(datetime_str):
126128

127129
def main():
128130
args = parse_args()
129-
token = args.token
131+
132+
if args.token:
133+
tokens = [args.token]
134+
else:
135+
tokens = git_logger.get_tokens_from_file(args.tokens)
136+
130137
repositories = args.list
131138
csv_name = args.out
132139
path_drepo = args.download_repos
133140
fork_flag = args.forks_include
134141
log_pr_comments = args.pr_comments
135142

136143
try:
137-
client = git_logger.login(token=token)
144+
clients = git_logger.GithubClients(tokens)
138145
except Exception as e:
139146
print(e)
140147
else:
141-
working_repos = git_logger.get_next_repo(client, repositories)
148+
working_repos = git_logger.get_next_repo(clients, repositories)
142149
start = parse_time(args.start.split('-'))
143150
finish = parse_time(args.finish.split('-'))
144151

145152
if args.commits:
146153
commits_parser.log_commits(
147-
client, working_repos, csv_name, start, finish, args.branch, fork_flag
154+
working_repos, csv_name, start, finish, args.branch, fork_flag
148155
)
149156
if args.pull_requests:
150157
pull_requests_parser.log_pull_requests(
151-
client,
152158
working_repos,
153159
csv_name,
154-
token,
155160
start,
156161
finish,
157162
fork_flag,
158163
log_pr_comments,
159164
)
160165
if args.issues:
161-
issues_parser.log_issues(
162-
client, working_repos, csv_name, token, start, finish, fork_flag
163-
)
166+
issues_parser.log_issues(working_repos, csv_name, start, finish, fork_flag)
164167
if args.invites:
165-
invites_parser.log_invitations(client, working_repos, csv_name)
168+
invites_parser.log_invitations(working_repos, csv_name)
166169
if args.wikis:
167-
wikipars.wikiparser(client, repositories, path_drepo, csv_name)
170+
wikipars.wikiparser(clients, repositories, path_drepo, csv_name)
168171
if args.contributors:
169-
contributors_parser.log_contributors(
170-
client, working_repos, csv_name, fork_flag
171-
)
172+
contributors_parser.log_contributors(working_repos, csv_name, fork_flag)
172173
if args.export_google_sheets:
173174
export_sheets.write_data_to_table(
174175
csv_name, args.google_token, args.table_id, args.sheet_id

pull_requests_parser.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import requests
44
import json
55
from time import sleep
6-
from git_logger import get_assignee_story
6+
from git_logger import get_assignee_story, GithubClients
77
from github import Github, Repository, GithubException, PullRequest
88

99
EMPTY_FIELD = 'Empty field'
@@ -161,26 +161,29 @@ def log_repositories_pr(
161161

162162

163163
def log_pull_requests(
164-
client: Github,
165164
working_repos,
166165
csv_name,
167-
token,
168166
start,
169167
finish,
170168
fork_flag,
171169
log_comments=False,
172170
):
173171
logger.log_to_csv(csv_name, FIELDNAMES)
174172

175-
for repo in working_repos:
173+
for repo, token in working_repos:
176174
try:
177175
logger.log_title(repo.full_name)
178176
log_repositories_pr(repo, csv_name, token, start, finish)
179177
if fork_flag:
180178
for forked_repo in repo.get_forks():
181179
logger.log_title("FORKED:", forked_repo.full_name)
182180
log_repositories_pr(
183-
forked_repo, csv_name, token, start, finish, log_comments
181+
forked_repo,
182+
csv_name,
183+
token,
184+
start,
185+
finish,
186+
log_comments,
184187
)
185188
sleep(TIMEDELTA)
186189
sleep(TIMEDELTA)

0 commit comments

Comments
 (0)