Skip to content

Commit a298d69

Browse files
authored
Workflow runs parser (#113)
1 parent 9457b22 commit a298d69

File tree

10 files changed

+169
-30
lines changed

10 files changed

+169
-30
lines changed

.github/workflows/smoke-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
- "--issues"
1818
- "--wikis"
1919
- "--contributors"
20+
- "--workflow_runs"
2021

2122
runs-on: ubuntu-latest
2223

GitHubRepoAPI.py

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
User,
1414
WikiPage,
1515
logging,
16+
WorkflowRun,
1617
)
1718

1819

@@ -37,7 +38,7 @@ def get_user_data(self, user) -> User:
3738
return User(
3839
login=user.login,
3940
username=user.name,
40-
email=user.email,
41+
email=user.email, # always None
4142
html_url=user.html_url,
4243
node_id=user.node_id,
4344
type=user.type,
@@ -46,6 +47,17 @@ def get_user_data(self, user) -> User:
4647
_id=user.id,
4748
)
4849

50+
def get_commit_data(self, commit, files=False) -> Commit:
51+
return Commit(
52+
_id=commit.sha,
53+
message=commit.commit.message,
54+
author=self.get_user_data(commit.author),
55+
date=commit.commit.author.date,
56+
files=[f.filename for f in commit.files] if files else None,
57+
additions=commit.stats.additions,
58+
deletions=commit.stats.deletions,
59+
)
60+
4961
def get_repository(self, id: str) -> Repository | None:
5062
try:
5163
repo = self.client.get_repo(id)
@@ -66,18 +78,8 @@ def get_collaborator_permission(self, repo: Repository, user: User) -> str:
6678
def get_commits(self, repo: Repository, files: bool = True) -> list[Commit]:
6779
try:
6880
commits = self.client.get_repo(repo._id).get_commits()
69-
return [
70-
Commit(
71-
_id=c.sha,
72-
message=c.commit.message,
73-
author=self.get_user_data(c.author),
74-
date=c.commit.author.date,
75-
files=[f.filename for f in c.files] if files else None,
76-
additions=c.stats.additions,
77-
deletions=c.stats.deletions,
78-
)
79-
for c in commits
80-
]
81+
return [self.get_commit_data(c, files) for c in commits]
82+
8183
except Exception as e:
8284
logging.error(
8385
f"Failed to get commits from GitHub for repo {repo.name}: {e}"
@@ -153,18 +155,7 @@ def get_branches(self, repo: Repository) -> list[Branch]:
153155
for branch in branches:
154156
commit = repo_client.get_commit(branch.commit.sha)
155157

156-
author = commit.author
157-
contributor = Contributor(
158-
username=author.login if author else "unknown",
159-
email=commit.commit.author.email or "",
160-
)
161-
162-
commit_obj = Commit(
163-
_id=commit.sha,
164-
message=commit.commit.message,
165-
author=contributor,
166-
date=commit.commit.author.date,
167-
)
158+
commit_obj = self.get_commit_data(commit)
168159

169160
result.append(Branch(name=branch.name, last_commit=commit_obj))
170161

@@ -182,10 +173,21 @@ def get_wiki_pages(self, repo: Repository) -> list[WikiPage]:
182173
def get_forks(self, repo: Repository) -> list[Repository]:
183174
repo_client = self.client.get_repo(repo._id)
184175
result = []
176+
185177
for r in repo_client.get_forks():
178+
default_branch = (Branch(name=r.default_branch, last_commit=None),)
179+
owner = (self.get_user_data(r.owner),)
180+
186181
result.append(
187-
Repository(_id=repo.full_name, name=repo.name, url=repo.html_url)
182+
Repository(
183+
_id=r.full_name,
184+
name=r.name,
185+
url=r.html_url,
186+
default_branch=default_branch,
187+
owner=owner,
188+
)
188189
)
190+
189191
return result
190192

191193
def get_comments(self, repo, obj) -> list[Comment]:
@@ -246,6 +248,34 @@ def get_invites(self, repo: Repository) -> list[Invite]:
246248
def get_rate_limiting(self) -> tuple[int, int]:
247249
return self.client.rate_limiting
248250

251+
def get_workflow_runs(self, repo) -> list[WorkflowRun]:
252+
try:
253+
runs = self.client.get_repo(repo._id).get_workflow_runs()
254+
255+
return [
256+
WorkflowRun(
257+
display_title=r.display_title,
258+
event=r.event,
259+
head_branch=r.head_branch,
260+
head_sha=r.head_sha,
261+
name=r.name,
262+
path=r.path,
263+
created_at=r.created_at,
264+
run_started_at=r.run_started_at,
265+
updated_at=r.updated_at,
266+
conclusion=r.conclusion,
267+
status=r.status,
268+
url=r.url,
269+
)
270+
for r in runs
271+
]
272+
273+
except Exception as e:
274+
logging.error(
275+
f"Failed to get workflow runs from GitHub for repo {repo.name}: {e}"
276+
)
277+
return []
278+
249279

250280
# Точка входа для тестирования
251281
if __name__ == "__main__":

commits_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def log_commits(
8484
log_repository_commits(client, repo, csv_name, start, finish, branch)
8585
if fork_flag:
8686
for forked_repo in client.get_forks(repo):
87-
logger.log_title("FORKED:", forked_repo.full_name)
87+
logger.log_title(f"FORKED: {forked_repo.name}")
8888
log_repository_commits(
8989
client, forked_repo, csv_name, start, finish, branch
9090
)

contributors_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def log_contributors(
9494

9595
if fork_flag:
9696
for forked_repo in client.get_forks(repo):
97-
logger.log_title("FORKED:", forked_repo.name)
97+
logger.log_title(f"FORKED: {forked_repo.name}")
9898
log_repository_contributors(client, forked_repo, csv_name)
9999
sleep(TIMEDELTA)
100100

interface_wrapper.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,22 @@ class WikiPage:
111111
content: str
112112

113113

114+
@dataclass
115+
class WorkflowRun:
116+
display_title: str
117+
event: str
118+
head_branch: str
119+
head_sha: str
120+
name: str
121+
path: str
122+
created_at: datetime
123+
run_started_at: datetime
124+
updated_at: datetime
125+
conclusion: str
126+
status: str
127+
url: str
128+
129+
114130
# Интерфейс API
115131
class IRepositoryAPI(ABC):
116132

@@ -173,6 +189,10 @@ def get_invites(self, repo: Repository) -> list[Invite]:
173189
def get_rate_limiting(self) -> tuple[int, int]:
174190
pass
175191

192+
@abstractmethod
193+
def get_workflow_runs(self, repo: Repository) -> list[WorkflowRun]:
194+
pass
195+
176196

177197
# Фабрика для создания API
178198
class RepositoryFactory:

issues_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def log_issues(
205205
if fork_flag:
206206
forked_repos = client.get_forks(repo)
207207
for forked_repo in forked_repos:
208-
logger.log_title("FORKED:", forked_repo.name)
208+
logger.log_title(f"FORKED: {forked_repo.name}")
209209
log_repository_issues(
210210
client, forked_repo, csv_name, token, start, finish
211211
)

main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import issues_parser
1010
import pull_requests_parser
1111
import wikipars
12+
import workflow_runs_parser
1213
from utils import parse_time
1314

1415

@@ -22,6 +23,9 @@ def parse_args():
2223
parser.add_argument("-i", "--issues", help="log issues", action="store_true")
2324
parser.add_argument("-w", "--wikis", help="log wikis", action="store_true")
2425
parser.add_argument("--contributors", help="log contributors", action="store_true")
26+
parser.add_argument(
27+
"--workflow_runs", help="log workflow runs", action="store_true"
28+
)
2529
parser.add_argument(
2630
"--forks_include", help="logging data from forks", action="store_true"
2731
)
@@ -144,6 +148,10 @@ def run(args, binded_repos, repos_for_wiki=None):
144148
)
145149
if args.contributors:
146150
contributors_parser.log_contributors(binded_repos, args.out, args.forks_include)
151+
if args.workflow_runs:
152+
workflow_runs_parser.log_workflow_runs(
153+
binded_repos, args.out, args.forks_include
154+
)
147155
if args.wikis:
148156
wikipars.wikiparser(repos_for_wiki, args.download_repos, args.out)
149157
if args.export_google_sheets:

pull_requests_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def log_pull_requests(
208208
if fork_flag:
209209
forked_repos = client.get_repo(repo._id).get_forks()
210210
for forked_repo in forked_repos:
211-
logger.log_title("FORKED:", forked_repo.full_name)
211+
logger.log_title(f"FORKED: {forked_repo.name}")
212212
log_repositories_pr(
213213
client,
214214
forked_repo,

test_token_usage.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def setUp(self):
4040
wikis=False,
4141
contributors=False,
4242
invites=False,
43+
workflow_runs=False,
4344
start="2000/01/01-00:00:00",
4445
finish="2400/01/01-00:00:00",
4546
branch="default",
@@ -88,6 +89,7 @@ def _get_usage(self, binded_repos, clients):
8889
param({'issues': True}, id='issues'),
8990
param({'invites': True}, id='invites'),
9091
param({'pull_requests': True}, id='pull_requests'),
92+
param({'workflow_runs': True}, id='workflow_runs'),
9193
],
9294
)
9395
def test_commits_parser(self, args: dict[str, bool]):

workflow_runs_parser.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from dataclasses import asdict, dataclass
2+
from time import sleep
3+
from typing import Generator
4+
5+
from constants import TIMEDELTA
6+
from interface_wrapper import IRepositoryAPI, Repository
7+
from utils import logger
8+
9+
10+
@dataclass(kw_only=True, frozen=True)
11+
class WorkflowRunData:
12+
repository_name: str = ''
13+
display_title: str = ''
14+
event: str = ''
15+
head_branch: str = ''
16+
head_sha: str = ''
17+
name: str = ''
18+
path: str = ''
19+
started_at: str = ''
20+
total_duration: float = 0.0
21+
conclusion: str = ''
22+
status: str = ''
23+
url: str = ''
24+
25+
26+
def log_repository_workflow_runs(
27+
client: IRepositoryAPI, repository: Repository, csv_name: str
28+
):
29+
workflow_runs = client.get_workflow_runs(repository)
30+
31+
for run in workflow_runs:
32+
total_duration = (run.updated_at - run.created_at).total_seconds()
33+
34+
workflow_run_data = WorkflowRunData(
35+
repository_name=repository.name,
36+
display_title=run.display_title,
37+
event=run.event,
38+
head_branch=run.head_branch,
39+
head_sha=run.head_sha,
40+
name=run.name,
41+
path=run.path,
42+
started_at=run.run_started_at,
43+
total_duration=total_duration,
44+
conclusion=run.conclusion,
45+
status=run.status,
46+
url=run.url,
47+
)
48+
49+
info_dict = asdict(workflow_run_data)
50+
51+
logger.log_to_csv(csv_name, list(info_dict.keys()), info_dict)
52+
logger.log_to_stdout(info_dict)
53+
54+
sleep(TIMEDELTA)
55+
56+
57+
def log_workflow_runs(
58+
binded_repos: Generator[tuple[IRepositoryAPI, Repository, str], None, None],
59+
csv_name: str,
60+
fork_flag: bool,
61+
):
62+
info = asdict(WorkflowRunData())
63+
logger.log_to_csv(csv_name, list(info.keys()))
64+
65+
for client, repo, token in binded_repos:
66+
try:
67+
logger.log_title(repo.name)
68+
log_repository_workflow_runs(client, repo, csv_name)
69+
70+
if fork_flag:
71+
for forked_repo in client.get_forks(repo):
72+
logger.log_title(f"FORKED: {forked_repo.name}")
73+
log_repository_workflow_runs(client, forked_repo, csv_name)
74+
sleep(TIMEDELTA)
75+
76+
except Exception as e:
77+
print(e)
78+
exit(1)

0 commit comments

Comments
 (0)