diff --git a/ForgejoRepoAPI.py b/ForgejoRepoAPI.py index 920b871..dc05da6 100644 --- a/ForgejoRepoAPI.py +++ b/ForgejoRepoAPI.py @@ -1,21 +1,12 @@ -from interface_wrapper import ( - logging, - IRepositoryAPI, - Repository, - Commit, - Branch, - User, - Contributor, - Issue, - PullRequest, - WikiPage, - Comment, - Invite, -) import base64 import sys -from pyforgejo import PyforgejoApi + import isodate +from pyforgejo import PyforgejoApi + +from interface_wrapper import (Branch, Comment, Commit, Contributor, Invite, + IRepositoryAPI, Issue, PullRequest, Repository, + User, WikiPage, logging) class ForgejoRepoAPI(IRepositoryAPI): diff --git a/GitHubRepoAPI.py b/GitHubRepoAPI.py index 239bdfe..ca7bd25 100644 --- a/GitHubRepoAPI.py +++ b/GitHubRepoAPI.py @@ -1,17 +1,6 @@ -from interface_wrapper import ( - logging, - Repository, - Contributor, - Commit, - Issue, - PullRequest, - WikiPage, - Branch, - IRepositoryAPI, - User, - Comment, - Invite, -) +from interface_wrapper import (Branch, Comment, Commit, Contributor, Invite, + IRepositoryAPI, Issue, PullRequest, Repository, + User, WikiPage, logging) class GitHubRepoAPI(IRepositoryAPI): diff --git a/commits_parser.py b/commits_parser.py index 0df8677..baa8de8 100644 --- a/commits_parser.py +++ b/commits_parser.py @@ -1,24 +1,22 @@ -from utils import logger -import pytz +from dataclasses import asdict, dataclass from time import sleep -# from github import Github, Repository, GithubException, PullRequest +import pytz + +from constants import EMPTY_FIELD, GOOGLE_MAX_CELL_LEN, TIMEDELTA, TIMEZONE from interface_wrapper import IRepositoryAPI, Repository +from utils import logger + -EMPTY_FIELD = 'Empty field' -TIMEDELTA = 0.05 -TIMEZONE = 'Europe/Moscow' -FIELDNAMES = ( - 'repository name', - 'author name', - 'author login', - 'author email', - 'date and time', - 'changed files', - 'commit id', - 'branch', -) -GOOGLE_MAX_CELL_LEN = 50000 +@dataclass(kw_only=True, frozen=True) +class CommitData: + repository_name: str = '' + author_name: str = '' + author_email: str = '' + datetime: str = '' + changed_files: str = '' + commit_id: str = '' + branch: str = '' def log_repository_commits( @@ -45,18 +43,19 @@ def log_repository_commits( continue changed_files = '; '.join([file for file in commit.files]) - commit_data = [ - repository.name, - commit.author.username, - commit.author.email or EMPTY_FIELD, - commit.date, - changed_files[:GOOGLE_MAX_CELL_LEN], - commit._id, - branch, - ] - info = dict(zip(FIELDNAMES, commit_data)) + changed_files = changed_files[:GOOGLE_MAX_CELL_LEN] + commit_data = CommitData( + repository_name=repository.name, + author_name=commit.author.username, + author_email=commit.author.email or EMPTY_FIELD, + datetime=commit.date.astimezone(pytz.timezone(TIMEZONE)).isoformat(), + changed_files=changed_files, + commit_id=commit._id, + branch=branch, + ) + info = asdict(commit_data) - logger.log_to_csv(csv_name, FIELDNAMES, info) + logger.log_to_csv(csv_name, list(info.keys()), info) logger.log_to_stdout(info) sleep(TIMEDELTA) @@ -65,7 +64,8 @@ def log_repository_commits( def log_commits( client: IRepositoryAPI, working_repos, csv_name, start, finish, branch, fork_flag ): - logger.log_to_csv(csv_name, FIELDNAMES) + info = asdict(CommitData()) + logger.log_to_csv(csv_name, list(info.keys())) for repo, token in working_repos: try: diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..68ab024 --- /dev/null +++ b/constants.py @@ -0,0 +1,18 @@ +EMPTY_FIELD = 'Empty field' +TIMEDELTA = 0.05 +TIMEZONE = 'Europe/Moscow' +GOOGLE_MAX_CELL_LEN = 50000 +TITLE_LEN = 80 +MIN_SIDE_PADDING = 4 +SIDE_WHITE_SPACES = 1 +WIKI_FIELDNAMES = [ + 'repository name', + 'author name', + 'author login', + 'datetime', + 'page', + 'action', + 'revision id', + 'added lines', + 'deleted lines', +] diff --git a/contributors_parser.py b/contributors_parser.py index 8a3110d..d07e654 100644 --- a/contributors_parser.py +++ b/contributors_parser.py @@ -1,25 +1,25 @@ -from utils import logger +from dataclasses import asdict, dataclass from time import sleep from typing import Generator + +from constants import EMPTY_FIELD, TIMEDELTA from interface_wrapper import IRepositoryAPI, Repository +from utils import logger + -EMPTY_FIELD = 'Empty field' -TIMEDELTA = 0.05 -TIMEZONE = 'Europe/Moscow' -FIELDNAMES = ( - 'repository name', - 'login', - 'name', - 'email', - 'url', - 'permissions', - 'total_commits', - 'id', - 'node_id', - 'type', - 'bio', - 'site_admin', -) +@dataclass(kw_only=True, frozen=True) +class ContributorData: + repository_name: str = '' + login: str = '' + name: str = '' + email: str = '' + url: str = '' + permissions: str = '' + total_commits: int = 0 + node_id: str = '' + type: str = '' + bio: str = '' + site_admin: bool = False def log_repository_contributors( @@ -36,22 +36,24 @@ def nvl(val): repository, contributor ) - info_tmp = { - 'repository name': repository.name, - 'login': contributor.login, - 'name': nvl(contributor.username), - 'email': nvl(contributor_stat['email']), - 'url': contributor.html_url, - 'permissions': nvl(contributor_permissions), - 'total_commits': contributor_stat['total_commits'], - 'node_id': contributor.node_id, - 'type': contributor.type, - 'bio': nvl(contributor.bio), - 'site_admin': contributor.site_admin, - } - - logger.log_to_csv(csv_name, FIELDNAMES, info_tmp) - logger.log_to_stdout(info_tmp) + contributor_data = ContributorData( + repository_name=repository.name, + login=contributor.login, + name=nvl(contributor.username), + email=nvl(contributor_stat['email']), + url=contributor.html_url, + permissions=nvl(contributor_permissions), + total_commits=contributor_stat['total_commits'], + node_id=contributor.node_id, + type=contributor.type, + bio=nvl(contributor.bio), + site_admin=contributor.site_admin, + ) + + info_dict = asdict(contributor_data) + + logger.log_to_csv(csv_name, list(info_dict.keys()), info_dict) + logger.log_to_stdout(info_dict) sleep(TIMEDELTA) @@ -80,7 +82,8 @@ def get_contributors_stats(client: IRepositoryAPI, repository: Repository) -> di def log_contributors( client: IRepositoryAPI, working_repos: Generator, csv_name: str, fork_flag: bool ): - logger.log_to_csv(csv_name, FIELDNAMES) + info = asdict(ContributorData()) + logger.log_to_csv(csv_name, list(info.keys())) for repo, token in working_repos: try: diff --git a/export_sheets.py b/export_sheets.py index 2188985..ed5a2dd 100644 --- a/export_sheets.py +++ b/export_sheets.py @@ -1,5 +1,5 @@ -import pygsheets import pandas as pd +import pygsheets INT_MASS = [{"one": 1, "two": 2, "what?": 3}] diff --git a/git_logger.py b/git_logger.py index 54f625c..ec7836b 100644 --- a/git_logger.py +++ b/git_logger.py @@ -1,8 +1,7 @@ -from interface_wrapper import RepositoryFactory, IRepositoryAPI from time import sleep -TIMEDELTA = 0.05 -TIMEZONE = 'Europe/Moscow' +from constants import TIMEDELTA +from interface_wrapper import IRepositoryAPI, RepositoryFactory def login(source, token, base_url): @@ -69,7 +68,6 @@ def get_next_repo(clients: GitClients, repositories): print(f'get_next_repo(): failed to load repository "{repo_name}"') exit(1) else: - print(cur_client['token']) yield repo, cur_client['token'] diff --git a/interface_wrapper.py b/interface_wrapper.py index 85e49bb..2afa503 100644 --- a/interface_wrapper.py +++ b/interface_wrapper.py @@ -1,7 +1,7 @@ +import logging from abc import ABC, abstractmethod -from datetime import datetime from dataclasses import dataclass -import logging +from datetime import datetime from github import Github from pyforgejo import PyforgejoApi @@ -178,8 +178,8 @@ class RepositoryFactory: def create_api( source: str, token: str, base_url: str | None = None ) -> IRepositoryAPI: - from GitHubRepoAPI import GitHubRepoAPI from ForgejoRepoAPI import ForgejoRepoAPI + from GitHubRepoAPI import GitHubRepoAPI if source == 'github': return GitHubRepoAPI(Github(token)) diff --git a/invites_parser.py b/invites_parser.py index f3275fb..167095e 100644 --- a/invites_parser.py +++ b/invites_parser.py @@ -1,45 +1,39 @@ -from utils import logger +from dataclasses import asdict, dataclass from time import sleep -from interface_wrapper import IRepositoryAPI, Repository -FIELDNAMES = ( - 'repository name', - 'invited login', - 'invite creation date', - 'invitation url', -) -TIMEDELTA = 0.05 +from constants import TIMEDELTA +from interface_wrapper import IRepositoryAPI, Repository +from utils import logger -def log_inviter(repo, invite, writer): - invite_info = [ - repo.full_name, - invite.invitee.login, - invite.created_at.strftime("%d/%m/%Y, %H:%M:%S"), - invite.html_url, - ] - writer.writerow(invite_info) - print(invite_info) +@dataclass(kw_only=True, frozen=True) +class InviteData: + repository_name: str = '' + invited_login: str = '' + invite_creation_date: str = '' + invitation_url: str = '' def log_repository_invitations( - client: IRepositoryAPI, repository: Repository, csv_name + client: IRepositoryAPI, repository: Repository, csv_name: str ): invitations = client.get_invites(repository) for invite in invitations: - invite_info = { - 'repository name': repository.name, - 'invited login': invite.invitee.login, - 'invite creation date': invite.created_at.strftime("%d/%m/%Y, %H:%M:%S"), - 'invitation url': invite.html_url, - } - logger.log_to_csv(csv_name, FIELDNAMES, invite_info) - logger.log_to_stdout(invite_info) + invite_data = InviteData( + repository_name=repository.name, + invited_login=invite.invitee.login, + invite_creation_date=invite.created_at.strftime("%d/%m/%Y, %H:%M:%S"), + invitation_url=invite.html_url, + ) + invite_dict = asdict(invite_data) + logger.log_to_csv(csv_name, list(invite_dict.keys()), invite_dict) + logger.log_to_stdout(invite_dict) sleep(TIMEDELTA) -def log_invitations(client: IRepositoryAPI, working_repos, csv_name): - logger.log_to_csv(csv_name, FIELDNAMES) +def log_invitations(client: IRepositoryAPI, working_repos, csv_name: str): + info = asdict(InviteData()) + logger.log_to_csv(csv_name, list(info.keys())) for repo, token in working_repos: logger.log_title(repo.name) diff --git a/issues_parser.py b/issues_parser.py index 17c6757..bd1d72c 100644 --- a/issues_parser.py +++ b/issues_parser.py @@ -1,38 +1,44 @@ -from utils import logger -import pytz -import requests import json +from dataclasses import asdict, dataclass from time import sleep + +import pytz +import requests + +from constants import EMPTY_FIELD, TIMEDELTA, TIMEZONE from git_logger import get_assignee_story from interface_wrapper import IRepositoryAPI, Repository +from utils import logger + + +@dataclass(kw_only=True, frozen=True) +class IssueData: + repository_name: str = '' + number: int = 0 + title: str = '' + state: str = '' + task: str = '' + created_at: str = '' + creator_name: str = '' + creator_login: str = '' + creator_email: str = '' + closed_at: str | None = None + closer_name: str | None = None + closer_login: str | None = None + closer_email: str | None = None + assignee_story: str = '' + connected_pull_requests: str = '' + labels: str = '' + milestone: str = '' -EMPTY_FIELD = 'Empty field' -TIMEDELTA = 0.05 -TIMEZONE = 'Europe/Moscow' -FIELDNAMES = ( - 'repository name', - 'number', - 'title', - 'state', - 'task', - 'created at', - 'creator name', - 'creator login', - 'creator email', - 'closer name', - 'closer login', - 'closer email', - 'closed at', - 'comment body', - 'comment created at', - 'comment author name', - 'comment author login', - 'comment author email', - 'assignee story', - 'connected pull requests', - 'labels', - 'milestone', -) + +@dataclass(kw_only=True, frozen=True) +class IssueDataWithComment(IssueData): + body: str = '' + created_at: str = '' + author_name: str = '' + author_login: str = '' + author_email: str = '' def get_connected_pulls(issue_number, repo_owner, repo_name, token): @@ -122,6 +128,7 @@ def get_info(obj, attr): return EMPTY_FIELD if obj is None else getattr(obj, attr) issues = client.get_issues(repository) + for issue in issues: if ( issue.created_at.astimezone(pytz.timezone(TIMEZONE)) < start @@ -129,63 +136,61 @@ def get_info(obj, attr): ): continue - info_tmp = { - 'repository name': repository.name, - 'number': issue._id, - 'title': issue.title, - 'state': issue.state, - 'task': issue.body, - 'created at': issue.created_at, - 'creator name': issue.user.username, - 'creator login': issue.user.login, - 'creator email': issue.user.email, - 'closed at': nvl(issue.closed_at), - 'closer name': issue.closed_by.username if issue.closed_by else None, - 'closer login': issue.closed_by.login if issue.closed_by else None, - 'closer email': issue.closed_by.email if issue.closed_by else None, - 'comment body': EMPTY_FIELD, - 'comment created at': EMPTY_FIELD, - 'comment author name': EMPTY_FIELD, - 'comment author login': EMPTY_FIELD, - 'comment author email': EMPTY_FIELD, - 'assignee story': get_assignee_story(issue), - 'connected pull requests': ( - EMPTY_FIELD - if issue._id is None - else get_connected_pulls( - issue._id, repository.owner, repository.name, token - ) - ), - 'labels': ( - EMPTY_FIELD - if issue.labels is None - else ';'.join([label for label in issue.labels]) + issue_data = IssueData( + repository_name=repository.name, + number=issue._id, + title=issue.title, + state=issue.state, + task=issue.body, + created_at=str(issue.created_at), + creator_name=issue.user.username, + creator_login=issue.user.login, + creator_email=issue.user.email, + closed_at=nvl(issue.closed_at), + closer_name=issue.closed_by.username if issue.closed_by else None, + closer_login=issue.closed_by.login if issue.closed_by else None, + closer_email=issue.closed_by.email if issue.closed_by else None, + assignee_story=get_assignee_story(issue), + connected_pull_requests=( + get_connected_pulls(issue._id, repository.owner, repository.name, token) + if issue._id is not None + else EMPTY_FIELD ), - 'milestone': get_info(issue.milestone, 'title'), - } - comments = client.get_comments(repository, issue) - if len(comments) > 0: - for comment in comments: - info = info_tmp - info['comment body'] = comment.body - info['comment created at'] = comment.created_at - info['comment author name'] = comment.author.username - info['comment author login'] = comment.author.login - info['comment author email'] = comment.author.email - - logger.log_to_csv(csv_name, FIELDNAMES, info) - logger.log_to_stdout(info) - else: - logger.log_to_csv(csv_name, FIELDNAMES, info_tmp) - logger.log_to_stdout(info_tmp) + labels=';'.join(issue.labels) if issue.labels else EMPTY_FIELD, + milestone=get_info(issue.milestone, 'title'), + ) + comments = client.get_comments(repository, issue) + log_issue_and_comments(csv_name, issue_data, comments) sleep(TIMEDELTA) +def log_issue_and_comments(csv_name, issue_data: IssueData, comments): + if comments: + for comment in comments: + comment_data = IssueDataWithComment( + **issue_data, + body=comment.body, + created_at=str(comment.created_at), + author_name=comment.author.username, + author_login=comment.author.login, + author_email=comment.author.email, + ) + comment_data = asdict(comment_data) + + logger.log_to_csv(csv_name, list(comment_data.keys()), comment_data) + logger.log_to_stdout(comment_data) + else: + info = asdict(issue_data) + logger.log_to_csv(csv_name, list(info.keys()), info) + logger.log_to_stdout(info) + + def log_issues( client: IRepositoryAPI, working_repo, csv_name, token, start, finish, fork_flag ): - logger.log_to_csv(csv_name, FIELDNAMES) + info = asdict(IssueDataWithComment()) + logger.log_to_csv(csv_name, list(info.keys())) for repo, token in working_repo: try: diff --git a/main.py b/main.py index 7c7585b..f44fbff 100644 --- a/main.py +++ b/main.py @@ -1,17 +1,18 @@ import argparse -from datetime import datetime -import pytz import traceback +from datetime import datetime +import pytz -import git_logger -import export_sheets import commits_parser -import pull_requests_parser -import issues_parser +import contributors_parser +import export_sheets +import git_logger import invites_parser +import issues_parser +import pull_requests_parser import wikipars -import contributors_parser +from constants import TIMEZONE from interface_wrapper import RepositoryFactory @@ -134,7 +135,7 @@ def parse_time(datetime_str): minute=start[4], second=start[5], ) - return start_datetime.astimezone(pytz.timezone(git_logger.TIMEZONE)) + return start_datetime.astimezone(pytz.timezone(TIMEZONE)) def main(): diff --git a/pull_requests_parser.py b/pull_requests_parser.py index ff5b18f..9ab2bba 100644 --- a/pull_requests_parser.py +++ b/pull_requests_parser.py @@ -1,41 +1,47 @@ -from utils import logger -import pytz -import requests import json +from dataclasses import asdict, dataclass from time import sleep + +import pytz +import requests + +from constants import EMPTY_FIELD, TIMEDELTA, TIMEZONE from git_logger import get_assignee_story from interface_wrapper import IRepositoryAPI, Repository +from utils import logger + -EMPTY_FIELD = 'Empty field' -TIMEDELTA = 0.05 -TIMEZONE = 'Europe/Moscow' -FIELDNAMES = ( - 'repository name', - 'title', - 'id', - 'state', - 'commit into', - 'commit from', - 'created at', - 'creator name', - 'creator login', - 'creator email', - 'changed files', - 'comment body', - 'comment created at', - 'comment author name', - 'comment author login', - 'comment author email', - 'merger name', - 'merger login', - 'merger email', - 'source branch', - 'target branch', - 'assignee story', - 'related issues', - 'labels', - 'milestone', -) +@dataclass(kw_only=True, frozen=True) +class PullRequestData: + repository_name: str = '' + title: str = '' + id: int = 0 + state: str = '' + commit_into: str = '' + commit_from: str = '' + created_at: str = '' + creator_name: str = '' + creator_login: str = '' + creator_email: str = '' + changed_files: str = '' + merger_name: str | None = None + merger_login: str | None = None + merger_email: str | None = None + source_branch: str = '' + target_branch: str = '' + assignee_story: str = '' + related_issues: str = '' + labels: str = '' + milestone: str = '' + + +@dataclass(kw_only=True, frozen=True) +class PullRequestDataWithComment(PullRequestData): + body: str = '' + created_at: str = '' + author_name: str = '' + author_login: str = '' + author_email: str = '' def get_related_issues(pull_request_number, repo_owner, repo_name, token): @@ -94,6 +100,14 @@ def get_related_issues(pull_request_number, repo_owner, repo_name, token): return ';'.join(list_issues_url) +def nvl(val): + return val or EMPTY_FIELD + + +def get_info(obj, attr): + return EMPTY_FIELD if obj is None else getattr(obj, attr) + + def log_repositories_pr( client: IRepositoryAPI, repository: Repository, @@ -117,60 +131,58 @@ def get_info(obj, attr): ): continue - info_tmp = { - 'repository name': repository.name, - 'title': pull.title, - 'id': pull._id, - 'state': pull.state, - 'commit into': pull.base_label, - 'commit from': pull.head_label, - 'created at': pull.created_at, - 'creator name': nvl(pull.author.username), - 'creator login': pull.author.login, - 'creator email': pull.author.email, - 'changed files': '; '.join([file for file in pull.files]), - 'comment body': EMPTY_FIELD, - 'comment created at': EMPTY_FIELD, - 'comment author name': EMPTY_FIELD, - 'comment author login': EMPTY_FIELD, - 'comment author email': EMPTY_FIELD, - 'merger name': pull.merged_by.username if pull.merged_by else None, - 'merger login': pull.merged_by.login if pull.merged_by else None, - 'merger email': pull.merged_by.email if pull.merged_by else None, - 'source branch': pull.head_ref, - 'target branch': pull.base_ref, - 'assignee story': get_assignee_story(pull), - 'related issues': ( - EMPTY_FIELD - if pull.issue_url is None - else get_related_issues( - pull._id, repository.owner, repository.name, token - ) + pr_data = PullRequestData( + repository_name=repository.name, + title=pull.title, + id=pull._id, + state=pull.state, + commit_into=pull.base_label, + commit_from=pull.head_label, + created_at=str(pull.created_at), + creator_name=nvl(pull.author.username), + creator_login=pull.author.login, + creator_email=pull.author.email, + changed_files='; '.join(pull.files), + merger_name=pull.merged_by.username if pull.merged_by else None, + merger_login=pull.merged_by.login if pull.merged_by else None, + merger_email=pull.merged_by.email if pull.merged_by else None, + source_branch=pull.head_ref, + target_branch=pull.base_ref, + assignee_story=get_assignee_story(pull), + related_issues=( + get_related_issues(pull._id, repository.owner, repository.name, token) + if pull.issue_url is not None + else EMPTY_FIELD ), - 'labels': ( - EMPTY_FIELD - if pull.labels is None - else ';'.join([label for label in pull.labels]) - ), - 'milestone': get_info(pull.milestone, 'title'), - } + labels=';'.join(pull.labels) if pull.labels else EMPTY_FIELD, + milestone=get_info(pull.milestone, 'title'), + ) if log_comments: comments = client.get_comments(repository, pull) - if len(comments) > 0: + if comments: for comment in comments: - info = info_tmp - info['comment body'] = comment.body - info['comment created at'] = comment.created_at - info['comment author name'] = comment.author.name - info['comment author login'] = comment.author.login - info['comment author email'] = nvl(comment.author.email) - - logger.log_to_csv(csv_name, FIELDNAMES, info) - logger.log_to_stdout(info) + comment_data = PullRequestDataWithComment( + **pr_data, + body=comment.body, + created_at=str(comment.created_at), + author_name=comment.author.name, + author_login=comment.author.login, + author_email=nvl(comment.author.email), + ) + comment_data = asdict(comment_data) + + logger.log_to_csv(csv_name, list(comment_data.keys()), comment_data) + logger.log_to_stdout(comment_data) + else: + base_pr_info = asdict(pr_data) + logger.log_to_csv(csv_name, list(base_pr_info.keys()), base_pr_info) + logger.log_to_stdout(base_pr_info) else: - logger.log_to_csv(csv_name, FIELDNAMES, info_tmp) - logger.log_to_stdout(info_tmp) + base_pr_info = asdict(pr_data) + logger.log_to_csv(csv_name, list(base_pr_info.keys()), base_pr_info) + logger.log_to_stdout(base_pr_info) + sleep(TIMEDELTA) @@ -183,7 +195,8 @@ def log_pull_requests( fork_flag, log_comments=False, ): - logger.log_to_csv(csv_name, FIELDNAMES) + info = asdict(PullRequestDataWithComment()) + logger.log_to_csv(csv_name, list(info.keys())) for repo, token in working_repos: try: diff --git a/utils.py b/utils.py index 0b8c842..1952a1b 100644 --- a/utils.py +++ b/utils.py @@ -1,8 +1,6 @@ import csv -TITLE_LEN = 80 -MIN_SIDE_PADDING = 4 -SIDE_WHITE_SPACES = 1 +from constants import MIN_SIDE_PADDING, SIDE_WHITE_SPACES, TITLE_LEN class logger: diff --git a/wikipars.py b/wikipars.py index 198661d..9d82851 100644 --- a/wikipars.py +++ b/wikipars.py @@ -1,19 +1,10 @@ -from git import Repo, exc +import csv import os import time -import csv -WIKI_FIELDNAMES = [ - 'repository name', - 'author name', - 'author login', - 'datetime', - 'page', - 'action', - 'revision id', - 'added lines', - 'deleted lines', -] +from git import Repo, exc + +from constants import WIKI_FIELDNAMES def log_wiki_to_csv(info, csv_name):