|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import re |
| 6 | +from datetime import datetime |
| 7 | +from datetime import timedelta |
| 8 | +from datetime import timezone |
| 9 | +from typing import Dict |
6 | 10 |
|
7 | 11 | from github import Github |
8 | 12 | from github.GithubException import GithubException |
| 13 | +from github.GithubException import UnknownObjectException |
9 | 14 |
|
10 | 15 | import colrev.record.record |
11 | 16 | import colrev.record.record_prep |
@@ -84,6 +89,122 @@ def _set_nr_commits(record_dict: dict, repo: Github.Repository.Repository) -> No |
84 | 89 | pass |
85 | 90 |
|
86 | 91 |
|
| 92 | +def _set_issue_counts(record_dict: dict, repo: Github.Repository.Repository) -> None: |
| 93 | + try: |
| 94 | + open_ = repo.get_issues(state="open").totalCount |
| 95 | + closed = repo.get_issues(state="closed").totalCount |
| 96 | + record_dict[Fields.GITHUB_ISSUE_COUNT_OPEN] = open_ |
| 97 | + record_dict[Fields.GITHUB_ISSUE_COUNT_CLOSED] = closed |
| 98 | + record_dict[Fields.GITHUB_ISSUE_COUNT_TOTAL] = open_ + closed |
| 99 | + except GithubException: |
| 100 | + record_dict[Fields.GITHUB_ISSUE_COUNT_OPEN] = 0 |
| 101 | + record_dict[Fields.GITHUB_ISSUE_COUNT_CLOSED] = 0 |
| 102 | + record_dict[Fields.GITHUB_ISSUE_COUNT_TOTAL] = 0 |
| 103 | + |
| 104 | + |
| 105 | +def _set_stars_watch_forks( |
| 106 | + record_dict: dict, repo: Github.Repository.Repository |
| 107 | +) -> None: |
| 108 | + try: |
| 109 | + record_dict[Fields.GITHUB_STAR_COUNT] = ( |
| 110 | + getattr(repo, "stargazers_count", 0) or 0 |
| 111 | + ) |
| 112 | + except GithubException: |
| 113 | + record_dict[Fields.GITHUB_STAR_COUNT] = 0 |
| 114 | + try: |
| 115 | + record_dict[Fields.GITHUB_WATCHER_COUNT] = ( |
| 116 | + getattr(repo, "subscribers_count", 0) or 0 |
| 117 | + ) |
| 118 | + except GithubException: |
| 119 | + record_dict[Fields.GITHUB_WATCHER_COUNT] = 0 |
| 120 | + try: |
| 121 | + record_dict[Fields.GITHUB_FORK_COUNT] = getattr(repo, "forks_count", 0) or 0 |
| 122 | + except GithubException: |
| 123 | + record_dict[Fields.GITHUB_FORK_COUNT] = 0 |
| 124 | + |
| 125 | + |
| 126 | +def _set_archive_status(record_dict: dict, repo: Github.Repository.Repository) -> None: |
| 127 | + try: |
| 128 | + is_archived = bool(getattr(repo, "archived", False)) |
| 129 | + record_dict[Fields.GITHUB_REPO_IS_ARCHIVED] = is_archived |
| 130 | + if is_archived: |
| 131 | + pushed_at = getattr(repo, "pushed_at", None) |
| 132 | + if pushed_at: |
| 133 | + record_dict[Fields.GITHUB_REPO_IS_ARCHIVED_DATE] = pushed_at.strftime( |
| 134 | + "%Y-%m-%d" |
| 135 | + ) |
| 136 | + except GithubException: |
| 137 | + record_dict[Fields.GITHUB_REPO_IS_ARCHIVED] = False |
| 138 | + |
| 139 | + |
| 140 | +def _set_last_commit_date( |
| 141 | + record_dict: dict, repo: Github.Repository.Repository |
| 142 | +) -> None: |
| 143 | + try: |
| 144 | + c = repo.get_commits()[0] |
| 145 | + dt = c.commit.author.date |
| 146 | + record_dict[Fields.GITHUB_COMMIT_LAST_DATE] = dt.strftime("%Y-%m-%d") |
| 147 | + except (GithubException, IndexError): |
| 148 | + pass |
| 149 | + |
| 150 | + |
| 151 | +def _set_latest_release_date( |
| 152 | + record_dict: dict, repo: Github.Repository.Repository |
| 153 | +) -> None: |
| 154 | + try: |
| 155 | + rel = repo.get_latest_release() |
| 156 | + if rel and getattr(rel, "published_at", None): |
| 157 | + record_dict[Fields.GITHUB_LATEST_RELEASE_DATE] = rel.published_at.strftime( |
| 158 | + "%Y-%m-%d" |
| 159 | + ) |
| 160 | + except (UnknownObjectException, GithubException): |
| 161 | + pass |
| 162 | + |
| 163 | + |
| 164 | +def _calc_language_percentages(repo: Github.Repository.Repository) -> Dict[str, float]: |
| 165 | + try: |
| 166 | + lang_bytes = repo.get_languages() |
| 167 | + total = sum(lang_bytes.values()) or 0 |
| 168 | + if total == 0: |
| 169 | + return {} |
| 170 | + return {k: round((v / total) * 100.0, 2) for k, v in lang_bytes.items()} |
| 171 | + except GithubException: |
| 172 | + return {} |
| 173 | + |
| 174 | + |
| 175 | +def _set_languages_pct(record_dict: dict, repo: Github.Repository.Repository) -> None: |
| 176 | + lang_pct = _calc_language_percentages(repo) |
| 177 | + if lang_pct: |
| 178 | + record_dict[Fields.GITHUB_LANGUAGES_PCT] = lang_pct |
| 179 | + |
| 180 | + |
| 181 | +def _set_branch_statuses(record_dict: dict, repo: Github.Repository.Repository) -> None: |
| 182 | + try: |
| 183 | + branches = list(repo.get_branches()) |
| 184 | + except GithubException: |
| 185 | + return |
| 186 | + |
| 187 | + active = stale = 0 |
| 188 | + now = datetime.now(timezone.utc) |
| 189 | + threshold = now - timedelta(days=90) |
| 190 | + |
| 191 | + for br in branches: |
| 192 | + try: |
| 193 | + sha = br.commit.sha |
| 194 | + commit = repo.get_commit(sha) |
| 195 | + dt = commit.commit.author.date |
| 196 | + if dt >= threshold: |
| 197 | + active += 1 |
| 198 | + else: |
| 199 | + stale += 1 |
| 200 | + except GithubException: |
| 201 | + stale += 1 |
| 202 | + |
| 203 | + record_dict[Fields.GITHUB_BRANCH_COUNT_ACTIVE] = active |
| 204 | + record_dict[Fields.GITHUB_BRANCH_COUNT_STALE] = stale |
| 205 | + record_dict[Fields.GITHUB_BRANCH_COUNT_ALL] = active + stale |
| 206 | + |
| 207 | + |
87 | 208 | def _update_record_based_on_citation_cff( |
88 | 209 | record_dict: dict, repo: Github.Repository.Repository |
89 | 210 | ) -> dict: |
@@ -114,11 +235,22 @@ def repo_to_record( |
114 | 235 | Fields.URL: repo.html_url, |
115 | 236 | Fields.ABSTRACT: repo.description, |
116 | 237 | Fields.GITHUB_LANGUAGE: repo.language, |
| 238 | + # Basic info triplet |
| 239 | + Fields.GITHUB_BASIC_INFO_OWNER: repo.owner.login, |
| 240 | + Fields.GITHUB_BASIC_INFO_REPO: repo.name, |
| 241 | + Fields.GITHUB_BASIC_INFO_URL: repo.html_url, |
117 | 242 | } |
118 | 243 |
|
119 | 244 | _set_license(record_dict, repo) |
120 | 245 | _set_nr_contributors(record_dict, repo) |
121 | 246 | _set_nr_commits(record_dict, repo) |
| 247 | + _set_issue_counts(record_dict, repo) |
| 248 | + _set_stars_watch_forks(record_dict, repo) |
| 249 | + _set_archive_status(record_dict, repo) |
| 250 | + _set_last_commit_date(record_dict, repo) |
| 251 | + _set_latest_release_date(record_dict, repo) |
| 252 | + _set_languages_pct(record_dict, repo) |
| 253 | + _set_branch_statuses(record_dict, repo) |
122 | 254 |
|
123 | 255 | # Use data from CITATION.cff file (if available) |
124 | 256 | _update_record_based_on_citation_cff(record_dict, repo) |
|
0 commit comments