Skip to content
Open

WIP #168

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.git
forgejo
Industrial_Nikolaev_AA_9381
reports
reports
output
18 changes: 0 additions & 18 deletions .github/workflows/collect_commits.yml

This file was deleted.

12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ docker run -v $(pwd)/output:/app/output checking_repo [--invites] [--commites] [
6. Нажимаем Generate token, сохраняем код токена и пользуемся.

## Запуск приложения:
Без `--debug` выводятся прогресс записи CSV раз в 5 секунд, итоговое число строк,
предупреждения и ошибки. Параметр `--debug` включает подробные логи отдельных записей.
CSV-файл и writer переиспользуются, после каждой строки вызывается `flush()`:
уже записанные строки сохраняются при обрыве процесса, файл закрывается при завершении обработки.

1. Логирование commits
```commandline
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 - логгировать все коммиты изо всех веток)
Expand All @@ -41,6 +46,13 @@ python3 main.py [-i, --issues] (-t token (github токен вместо token)
```commandline
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)
```
Для прямой выгрузки PR из БД Forgejo (`--source forgejo_db`) можно добавить
`--forgejo-db-organization my-org --forgejo-db-repo-name-contains 2026 2027`:
выбираются PR репозиториев владельца `my-org`, имя которых содержит `2026`
**или** `2027`. Оба фильтра необязательны, применяются в SQL без учёта регистра;
организация задаётся точным логином, подстроки имени трактуются буквально.
Без фильтров выгружаются все PR инстанса; `--list` выборку PR не ограничивает.

4. Логирование непринятых приглашений в репо
```commandline
python3 main.py --invites (-t token (github токен вместо token) | --tokens tokens (путь до файла с токенами вместо tokens)) [-l, --list] list (list - строка пути к txt файлу со списком репозиториев) [-o, --out] out (out - название csv файла, в который будут помещены все логи)
Expand Down
138 changes: 92 additions & 46 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import logging
import traceback
import sys

Expand All @@ -11,18 +12,41 @@
from src import pull_requests_parser
from src import wikipars
from src import workflow_runs_parser
from src.utils import parse_time, validate_and_normalize_cell
from src.utils import logger, parse_time, validate_and_normalize_cell
from src.api.utils import APITypes


def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--debug", action="store_true", help="Enable detailed console logs")
parser.add_argument(
"--source",
choices=list(APITypes),
default=APITypes.github,
required=False,
help="Data source: github API (by default), forgejo API, forgejo db (direct access)",
)
parser.add_argument("--invites", help="print pending invites", action="store_true")
parser.add_argument(
"--forgejo-db-organization",
help="Forgejo DB only: exact repository owner login (case-insensitive)",
)
parser.add_argument(
"--forgejo-db-repo-name-contains",
nargs="+",
help=(
"Forgejo DB only: select repositories whose name contains any of "
"these literal substrings (case-insensitive), e.g. 2026 2027"
),
)
parser.add_argument("-c", "--commits", help="log commits", action="store_true")
parser.add_argument(
"-p", "--pull_requests", help="log pull requests", action="store_true"
)
parser.add_argument(
"--graphql", help="use graphql for requesting data (work only with --pull_requests) ", action="store_true"
"--graphql",
help="use graphql for requesting data (work only with --pull_requests) ",
action="store_true",
)
parser.add_argument("-i", "--issues", help="log issues", action="store_true")
parser.add_argument("-w", "--wikis", help="log wikis", action="store_true")
Expand All @@ -40,90 +64,90 @@ def parse_args():
action="store_true",
)
parser.add_argument(
'--start_cell',
"--start_cell",
type=str,
required=False,
help='Starting cell for Google Sheets export (e.g., "A1", "B3")',
default="A1"
default="A1",
)

parser.add_argument(
'--base_url',
"--base_url",
type=str,
required=False,
help='Base URL for Forgejo instance (if using Forgejo)',
help="Base URL for Forgejo instance (if using Forgejo)",
)

token = parser.add_mutually_exclusive_group(required=True)
token.add_argument('-t', '--token', type=str, help='account access token')
token.add_argument('--tokens', type=str, help='path to your tokens')
token.add_argument("-t", "--token", type=str, help="account access token")
token.add_argument("--tokens", type=str, help="path to your tokens")

parser.add_argument(
'-l',
'--list',
"-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 must be in the format <organization or owner>/<name> '
"Path to the file containing the list of repositories. "
"Repositories should be separated by a line break. "
"Names must be in the format <organization or owner>/<name> "
),
)
parser.add_argument(
"--download_repos",
type=str,
help="path to downloaded repositories",
default='./',
default="./",
)
parser.add_argument('-o', '--out', type=str, required=True, help='output filename')
parser.add_argument("-o", "--out", type=str, required=True, help="output filename")
parser.add_argument(
"--pr_comments", help="log comments for PR", action="store_true"
)
parser.add_argument(
'-s',
'--start',
"-s",
"--start",
type=str,
required=False,
help='start time',
default='2000/01/01-00:00:00',
help="start time",
default="2000/01/01-00:00:00",
)
parser.add_argument(
'-f',
'--finish',
"-f",
"--finish",
type=str,
required=False,
help='finish time',
default='2400/01/01-00:00:00',
help="finish time",
default="2400/01/01-00:00:00",
)
parser.add_argument(
'-b',
'--branch',
"-b",
"--branch",
type=str,
required=False,
help=(
'branch to select commits, '
"branch to select commits, "
'by default use "default" repository branch, '
'use "all" to get all commits from all branches',
),
default=None,
)
parser.add_argument(
'--google_token',
"--google_token",
type=str,
required=False,
help='Specify path to google token file',
help="Specify path to google token file",
)
parser.add_argument(
'--table_id',
"--table_id",
type=str,
required=False,
help='Specify Google sheet document id (can find in url)',
help="Specify Google sheet document id (can find in url)",
)
parser.add_argument(
'--sheet_name',
"--sheet_name",
type=str,
required=False,
help='Specify title for a sheet in a document in which data will be printed',
help="Specify title for a sheet in a document in which data will be printed",
)
parser.add_argument(
"--clear_sheet",
Expand All @@ -135,18 +159,18 @@ def parse_args():

if args.export_google_sheets:
for action in parser._actions:
if action.dest == 'google_token':
if action.dest == "google_token":
action.required = True
if action.dest == 'table_id':
if action.dest == "table_id":
action.required = True
if action.dest == 'sheet_name':
if action.dest == "sheet_name":
action.required = True
return parser.parse_args()


def run(args, binded_repos, repos_for_wiki=None):
start = parse_time(args.start.split('-'))
finish = parse_time(args.finish.split('-'))
start = parse_time(args.start.split("-"))
finish = parse_time(args.finish.split("-"))

if args.commits:
commits_parser.log_commits(
Expand All @@ -155,8 +179,7 @@ def run(args, binded_repos, repos_for_wiki=None):
if args.pull_requests:
if args.graphql:
pull_requests_parser.log_pull_requests_by_graphql(
binded_repos=binded_repos,
csv_name=args.out
binded_repos=binded_repos, csv_name=args.out
)
else:
pull_requests_parser.log_pull_requests(
Expand All @@ -169,7 +192,12 @@ def run(args, binded_repos, repos_for_wiki=None):
)
if args.issues:
issues_parser.log_issues(
binded_repos, args.out, start, finish, args.forks_include, args.base_url,
binded_repos,
args.out,
start,
finish,
args.forks_include,
args.base_url,
)
if args.invites:
invites_parser.log_invitations(
Expand All @@ -185,6 +213,7 @@ def run(args, binded_repos, repos_for_wiki=None):
if args.wikis:
wikipars.wikiparser(repos_for_wiki, args.download_repos, args.out)
if args.export_google_sheets:
logger.close_csv_files()
export_sheets.write_data_to_table(
csv_path=args.out,
google_token=args.google_token,
Expand All @@ -197,11 +226,12 @@ def run(args, binded_repos, repos_for_wiki=None):

def main():
args = parse_args()
logging.getLogger().setLevel(logging.DEBUG if args.debug else logging.WARNING)

try:
args.start_cell = validate_and_normalize_cell(args.start_cell)
except ValueError as e:
print(f"Error in start_cell argument: {e}")
logging.error("Error in start_cell argument: %s", e)
sys.exit(1)

if args.token:
Expand All @@ -212,15 +242,31 @@ def main():
repositories = git_logger.get_repos_from_file(args.list)

try:
clients = git_logger.Clients(tokens, args.base_url)
clients = git_logger.Clients(
api_type=args.source,
auth_data=[
dict(
token=token,
base_url=args.base_url,
forgejo_db=dict(
repo_name_contains=args.forgejo_db_repo_name_contains,
organization=args.forgejo_db_organization,
),
)
for token in tokens
],
)
binded_repos = git_logger.get_next_binded_repo(clients, repositories)
except Exception as e:
print(f"Failed to initialize any clients: {e}")
print(traceback.format_exc())
logging.error("Failed to initialize any clients: %s", e)
logging.debug(traceback.format_exc())
return

run(args, binded_repos, repositories)
try:
run(args, binded_repos, repositories)
finally:
logger.close_csv_files()


if __name__ == '__main__':
if __name__ == "__main__":
main()
9 changes: 5 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
GitPython==3.1.41
isodate==0.7.2
pandas==2.2.3
psycopg2-binary==2.9.13
pyforgejo==2.0.7
PyGithub==2.4.0
pygsheets==2.0.6
pandas==2.2.3
pytz==2024.2
requests==2.32.3
pyforgejo==2.0.7
isodate==0.7.2
unittest-parametrize==1.6.0
unittest-parametrize==1.6.0
Loading
Loading