gitlogstats 1.5.2__tar.gz → 1.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/PKG-INFO +18 -2
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/README.md +17 -1
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/docs/SPEC.md +10 -0
- gitlogstats-1.6.0/docs/examples/project-1-stats.csv +126 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/pyproject.toml +1 -1
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/scripts/board/manifest.yaml +16 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/__main__.py +20 -6
- gitlogstats-1.6.0/src/gitlogstats/aggregate.py +177 -0
- gitlogstats-1.6.0/tests/test_aggregate.py +368 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/test_integration.py +260 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/CLAUDE.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/agents/developer-agent.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/agents/spec-reviewer.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/hooks/format-edited.sh +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/hooks/guard-paths.sh +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/hooks/guard-paths.test.mjs +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/hooks/verify.sh +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/settings.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/skills/phase-handoff/SKILL.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.claude/skills/stale-check/SKILL.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.github/workflows/build.yaml +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.gitignore +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/.prettierrc.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/LICENSE +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/Pipfile +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/Pipfile.lock +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/docs/examples/README.md +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/docs/examples/assignment-stats.sh +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/package-lock.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/package.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/repos.txt +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/requirements.txt +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/scripts/board/config.mjs +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/scripts/board/derive.mjs +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/scripts/board/derive.test.mjs +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/scripts/board/sync.mjs +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/__init__.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/clones.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/git_logs_parser.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/github.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/github_stats.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/src/gitlogstats/identity.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fake_gh.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/commit_linked.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/commit_unlinked.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/contributors.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/contributors_page2.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/pulls_page1.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/pulls_page2.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/user_full.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/fixtures/github/user_private.json +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/test_clobber.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/test_git_logs_parser.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/test_github.py +0 -0
- {gitlogstats-1.5.2 → gitlogstats-1.6.0}/tests/test_identity.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: gitlogstats
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: Track developers' contributions to one or more git repositories within a particular time range.
|
|
5
5
|
Project-URL: Homepage, https://github.com/bloombar/gitlogstats
|
|
6
6
|
Project-URL: Repository, https://github.com/bloombar/gitlogstats.git
|
|
@@ -726,7 +726,8 @@ The command `gitlogstats --help` shows the usage instructions:
|
|
|
726
726
|
```
|
|
727
727
|
usage: gitlogstats [-h] (-r REPOSITORY | -rf REPOFILE) [-u USER] [-s START]
|
|
728
728
|
[-e END] [-x EXCLUSIONS] [-f {csv,json,markdown}]
|
|
729
|
-
[-b BRANCH] [-v] [-c] [
|
|
729
|
+
[-b BRANCH] [-v] [-c] [-a {developer,repository}]
|
|
730
|
+
[--github] [--clobber]
|
|
730
731
|
|
|
731
732
|
options:
|
|
732
733
|
-h, --help show this help message and exit
|
|
@@ -751,6 +752,10 @@ options:
|
|
|
751
752
|
The branch to parse, if not the default branch
|
|
752
753
|
-v, --verbose Whether to output debugging info
|
|
753
754
|
-c, --clean Remove contributors without any contribuition
|
|
755
|
+
-a {developer,repository}, --aggregate {developer,repository}
|
|
756
|
+
Combine the results into one row per developer, summed
|
|
757
|
+
over all repositories, or one row per repository,
|
|
758
|
+
summed over its contributors
|
|
754
759
|
--github Also report GitHub pull requests opened, merged,
|
|
755
760
|
closed and self-merged per contributor, with their git
|
|
756
761
|
and GitHub emails, their pushes to the analyzed branch
|
|
@@ -840,6 +845,17 @@ By default, every contributor in a repository's history is listed, with zeros fo
|
|
|
840
845
|
gitlogstats -rf repos.txt -c
|
|
841
846
|
```
|
|
842
847
|
|
|
848
|
+
### Totals per developer or per repository
|
|
849
|
+
|
|
850
|
+
By default there is one row per contributor per repository. Add `-a developer` to get one row per developer with their statistics summed over every repository, or `-a repository` to get one row per repository summed over its contributors.
|
|
851
|
+
|
|
852
|
+
```
|
|
853
|
+
gitlogstats -rf repos.txt -a developer
|
|
854
|
+
gitlogstats -rf repos.txt -a repository
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
Developer rows have no `repository` column; instead a `repositories` column counts the repositories the developer was active in during the date range. Repository rows have no username or email columns; a `contributors` column counts the contributors who were active in the repository during the date range. `-u` and `-c` are applied first, so `-u alice -a repository` shows Alice's share of each repository. With `--github`, a developer's rows are combined by GitHub username, so different git names linked to one GitHub account become one row, and their email addresses are listed together. A developer matched to a GitHub account in one repository but not in another (for example a repository not on GitHub) keeps a separate row for each.
|
|
858
|
+
|
|
843
859
|
### Cloned repositories
|
|
844
860
|
|
|
845
861
|
Each repository is cloned into a `repos/` directory under the directory you run the command from, and later runs update (`git pull`) the existing clone instead of cloning again, which makes them much faster. Add `--clobber` to delete the clones the run used, once the results have been printed; `repos/` itself is removed too if nothing else is left in it. Clones from other runs are kept, and nothing is deleted if the run fails before printing, so you can inspect it. With `-v`, each deleted path is listed on standard error.
|
|
@@ -29,7 +29,8 @@ The command `gitlogstats --help` shows the usage instructions:
|
|
|
29
29
|
```
|
|
30
30
|
usage: gitlogstats [-h] (-r REPOSITORY | -rf REPOFILE) [-u USER] [-s START]
|
|
31
31
|
[-e END] [-x EXCLUSIONS] [-f {csv,json,markdown}]
|
|
32
|
-
[-b BRANCH] [-v] [-c] [
|
|
32
|
+
[-b BRANCH] [-v] [-c] [-a {developer,repository}]
|
|
33
|
+
[--github] [--clobber]
|
|
33
34
|
|
|
34
35
|
options:
|
|
35
36
|
-h, --help show this help message and exit
|
|
@@ -54,6 +55,10 @@ options:
|
|
|
54
55
|
The branch to parse, if not the default branch
|
|
55
56
|
-v, --verbose Whether to output debugging info
|
|
56
57
|
-c, --clean Remove contributors without any contribuition
|
|
58
|
+
-a {developer,repository}, --aggregate {developer,repository}
|
|
59
|
+
Combine the results into one row per developer, summed
|
|
60
|
+
over all repositories, or one row per repository,
|
|
61
|
+
summed over its contributors
|
|
57
62
|
--github Also report GitHub pull requests opened, merged,
|
|
58
63
|
closed and self-merged per contributor, with their git
|
|
59
64
|
and GitHub emails, their pushes to the analyzed branch
|
|
@@ -143,6 +148,17 @@ By default, every contributor in a repository's history is listed, with zeros fo
|
|
|
143
148
|
gitlogstats -rf repos.txt -c
|
|
144
149
|
```
|
|
145
150
|
|
|
151
|
+
### Totals per developer or per repository
|
|
152
|
+
|
|
153
|
+
By default there is one row per contributor per repository. Add `-a developer` to get one row per developer with their statistics summed over every repository, or `-a repository` to get one row per repository summed over its contributors.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
gitlogstats -rf repos.txt -a developer
|
|
157
|
+
gitlogstats -rf repos.txt -a repository
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Developer rows have no `repository` column; instead a `repositories` column counts the repositories the developer was active in during the date range. Repository rows have no username or email columns; a `contributors` column counts the contributors who were active in the repository during the date range. `-u` and `-c` are applied first, so `-u alice -a repository` shows Alice's share of each repository. With `--github`, a developer's rows are combined by GitHub username, so different git names linked to one GitHub account become one row, and their email addresses are listed together. A developer matched to a GitHub account in one repository but not in another (for example a repository not on GitHub) keeps a separate row for each.
|
|
161
|
+
|
|
146
162
|
### Cloned repositories
|
|
147
163
|
|
|
148
164
|
Each repository is cloned into a `repos/` directory under the directory you run the command from, and later runs update (`git pull`) the existing clone instead of cloning again, which makes them much faster. Add `--clobber` to delete the clones the run used, once the results have been printed; `repos/` itself is removed too if nothing else is left in it. Clones from other runs are kept, and nothing is deleted if the run fails before printing, so you can inspect it. With `-v`, each deleted path is listed on standard error.
|
|
@@ -202,6 +202,16 @@ When several repositories are analyzed, the results are printed once, after all
|
|
|
202
202
|
|
|
203
203
|
**Status:** Done
|
|
204
204
|
|
|
205
|
+
#### OUT-6 Aggregated results
|
|
206
|
+
|
|
207
|
+
`-a/--aggregate developer` prints one row per developer, summed over every repository analyzed, instead of one row per contributor per repository. Its columns are `username, start_date, end_date, commits, insertions, deletions, files, merges, repositories`, where `repositories` is the number of repositories in which the developer has any activity in the date range (a non-zero count, git or GitHub, as for `-c`); there is no `repository` column. With `--github`, the columns `github_username, prs_opened, prs_merged, prs_closed_unmerged, prs_self_merged, git_email, github_email, pushes_to_default, web_commits` follow. Rows are combined when they share a GitHub username (ignoring case), or, for rows without one, the same git `username` exactly; a developer matched to a GitHub user in one repository but not in another is reported as two rows. `username` is the git username of the developer's row with the most commits (ties alphabetical, as in STAT-11), `github_username` the first non-empty one among the developer's rows, and `git_email` and `github_email` list every distinct email of the combined rows, sorted alphabetically (ignoring case) and separated by `; `.
|
|
208
|
+
|
|
209
|
+
`-a/--aggregate repository` prints one row per repository, summed over its contributors. Its columns are `repository, start_date, end_date, commits, insertions, deletions, files, merges, contributors`, where `contributors` is the number of its contributors with any activity in the date range; with `--github`, `prs_opened, prs_merged, prs_closed_unmerged, prs_self_merged, pushes_to_default, web_commits` follow. There are no `username`, `github_username`, `git_email` or `github_email` columns.
|
|
210
|
+
|
|
211
|
+
In both modes every count is the sum of the combined rows, so each total equals the sum of the rows printed without `--aggregate`. A GitHub count is empty (`null` in JSON) only when it is empty in every combined row (CLI-3). Aggregation is applied after `-u` and `-c`, so it combines only the rows those options keep. Rows are sorted by `username` (or `github_username`, for a developer with no git username) or by `repository`, ignoring case. The aggregated columns are printed in every output format, and in the CSV header even when there are no rows. Without `-a`, the output is unchanged.
|
|
212
|
+
|
|
213
|
+
**Status:** Done
|
|
214
|
+
|
|
205
215
|
### 5. Command-Line Interface
|
|
206
216
|
|
|
207
217
|
#### CLI-1 Help and usage
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
username,repository,start_date,end_date,commits,insertions,deletions,files,merges,github_username,prs_opened,prs_merged,prs_closed_unmerged,prs_self_merged,git_email,github_email,pushes_to_default,web_commits
|
|
2
|
+
Jade Leong,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,4,124,45,4,0,Jade-Leong,1,1,0,0,jyl9618@nyu.edu,,2,0
|
|
3
|
+
Khidir Ahmed,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,4,9,6,4,0,khidirahmed,2,2,0,1,kka6822@nyu.edu,kka6822@nyu.edu,2,1
|
|
4
|
+
Pope,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,6,31,5,6,3,pope-cruz,4,4,0,3,168572503+pope-cruz@users.noreply.github.com; popecruz822@gmail.com,,1,0
|
|
5
|
+
sethderusha,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,10,55,34,10,7,sethderusha,2,2,0,2,165086066+sethderusha@users.noreply.github.com; srd6665@nyu.edu,,8,0
|
|
6
|
+
alissawu,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,1,1,0,1,0,alissawu,1,1,0,0,alissawu77@gmail.com,alissawu77@gmail.com,0,0
|
|
7
|
+
bloombar,specification-phase-exercise-sakjp,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
8
|
+
Dialloni,specification-phase-exercise-leodiajulce,09/01/2026,10/16/2026,5,130,6,6,3,Dialloni,0,0,0,0,119769795+Dialloni@users.noreply.github.com; dialoabo@gmail.com,,0,0
|
|
9
|
+
Jrleitersdorf,specification-phase-exercise-leodiajulce,09/01/2026,10/16/2026,4,437,13,5,2,Jrleitersdorf,0,0,0,0,jrleitersdorf@gmail.com,,0,0
|
|
10
|
+
Leonid2004,specification-phase-exercise-leodiajulce,09/01/2026,10/16/2026,3,189,6,3,3,Leonid2004,0,0,0,0,72578139+Leonid2004@users.noreply.github.com; leophilo7@gmail.com,,0,0
|
|
11
|
+
bloombar,specification-phase-exercise-leodiajulce,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
12
|
+
carinutza,specification-phase-exercise-leodiajulce,09/01/2026,10/16/2026,13,146,33,18,4,carinutza,0,0,0,0,ilie.carina@gmail.com,,1,0
|
|
13
|
+
YusefMoustafa,specification-phase-exercise-waterfall,09/01/2026,10/16/2026,6,119,7,6,0,YusefMoustafa,0,0,0,0,158067706+YusefMoustafa@users.noreply.github.com,,6,6
|
|
14
|
+
bloombar,specification-phase-exercise-waterfall,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
15
|
+
krishivseth,specification-phase-exercise-waterfall,09/01/2026,10/16/2026,7,555,23,10,1,krishivseth,2,2,0,2,93362198+krishivseth@users.noreply.github.com,,1,7
|
|
16
|
+
monica9482,specification-phase-exercise-waterfall,09/01/2026,10/16/2026,15,77,97,15,1,monica9482,0,0,0,0,ml9482@nyu.edu,,16,0
|
|
17
|
+
sing1179,specification-phase-exercise-waterfall,09/01/2026,10/16/2026,5,91,19,5,0,sing1179,0,0,0,0,143670921+sing1179@users.noreply.github.com,,5,5
|
|
18
|
+
Sarah Toussaint,specification-phase-exercise-tigers,09/01/2026,10/16/2026,3,50,2,3,0,sarahtoussaint,1,0,1,0,sat10002@nyu.edu,,3,3
|
|
19
|
+
bloombar,specification-phase-exercise-tigers,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
20
|
+
izz04,specification-phase-exercise-tigers,09/01/2026,10/16/2026,14,175,70,14,4,izz04,6,6,0,2,73780798+izz04@users.noreply.github.com,,9,14
|
|
21
|
+
jk8308-jpg,specification-phase-exercise-tigers,09/01/2026,10/16/2026,2,48,1,2,3,jk8308-jpg,2,2,0,0,jk8308@nyu.edu,,0,0
|
|
22
|
+
nonyembaezue,specification-phase-exercise-tigers,09/01/2026,10/16/2026,7,32,6,7,1,nonyembaezue,0,0,0,0,cam9137@nyu.edu,,7,7
|
|
23
|
+
bloombar,specification-exercise-project-1,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
24
|
+
sallyhegab,specification-exercise-project-1,09/01/2026,10/16/2026,5,109,14,5,1,sallyhegab,0,0,0,0,158313024+sallyhegab@users.noreply.github.com; sh6568@nyu.edu,,5,0
|
|
25
|
+
sar9249,specification-exercise-project-1,09/01/2026,10/16/2026,1,1,1,1,0,sar9249,1,1,0,0,sar9249@nyu.edu,,0,1
|
|
26
|
+
Ryan Lin,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,2,3,1,2,0,ryanwlin,0,0,0,0,ryanandlin@gmail.com,,2,2
|
|
27
|
+
berrizy,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,2,2,3,2,0,berrizy,0,0,0,0,nahasselma@gmail.com,,2,0
|
|
28
|
+
bloombar,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
29
|
+
rishachada,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,6,114,37,6,0,rishachada,0,0,0,0,rc5294@nyu.edu,,6,2
|
|
30
|
+
schauhans,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,2,24,3,2,0,schauhans,0,0,0,0,139730145+schauhans@users.noreply.github.com; sc10486@nyu.edu,,2,1
|
|
31
|
+
yufeiihuang,specification-phase-exercise-codekitchen,09/01/2026,10/16/2026,9,65,13,9,0,yufeiihuang,0,0,0,0,yufeixyhuang@gmail.com,,9,9
|
|
32
|
+
AmitavNarayan,specification-phase-exercise-no-ai-team,09/01/2026,10/16/2026,26,489,443,26,7,AmitavNarayan,6,6,0,6,amitavnarayan2@gmail.com,,21,8
|
|
33
|
+
Trisolis,specification-phase-exercise-no-ai-team,09/01/2026,10/16/2026,8,221,109,8,3,Trisolis,3,3,0,2,papijackwaiter@gmail.com,papijackwaiter@gmail.com,5,0
|
|
34
|
+
bloombar,specification-phase-exercise-no-ai-team,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
35
|
+
rfang1224,specification-phase-exercise-no-ai-team,09/01/2026,10/16/2026,3,9,5,3,0,rfang1224,1,1,0,0,rf2789@nyu.edu,,2,2
|
|
36
|
+
Abel200595,specification-phase-exercise-smart_monkeys-,09/01/2026,10/16/2026,1,507,1,4,0,Abel200595,0,0,0,0,ym3057@nyu.edu,,0,0
|
|
37
|
+
Jialiang Cao,specification-phase-exercise-smart_monkeys-,09/01/2026,10/16/2026,4,9,19,4,0,jialiangcao,0,0,0,0,jcao2080@gmail.com,,3,0
|
|
38
|
+
RayyanAhmed21,specification-phase-exercise-smart_monkeys-,09/01/2026,10/16/2026,7,252,111,7,5,RayyanAhmed21,5,5,0,5,ra4073@nyu.edu,,0,3
|
|
39
|
+
bloombar,specification-phase-exercise-smart_monkeys-,09/01/2026,10/16/2026,1,15,0,1,1,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
40
|
+
rz3007,specification-phase-exercise-smart_monkeys-,09/01/2026,10/16/2026,2,54,4,2,0,rz3007,0,0,0,0,rz3007@nyu.edu,,0,2
|
|
41
|
+
Asritha Pannem,specification-phase-exercise-controller,09/01/2026,10/16/2026,1,42,0,1,0,,0,0,0,0,asp9404@nyu.edu,,0,0
|
|
42
|
+
NISUN05,specification-phase-exercise-controller,09/01/2026,10/16/2026,6,106,7,6,0,NISUN05,0,0,0,0,na3755@nyu.edu,,6,0
|
|
43
|
+
Nishika Gorla,specification-phase-exercise-controller,09/01/2026,10/16/2026,3,32,4,3,0,nishikagorla,2,2,0,0,nishika.gorla@gmail.com,nishika.gorla@gmail.com,3,0
|
|
44
|
+
Pranay Engineer,specification-phase-exercise-controller,09/01/2026,10/16/2026,6,70,11,6,5,PranayEng,3,3,0,3,88552049+PranayEng@users.noreply.github.com; Pme7634@nyu.edu,,1,1
|
|
45
|
+
ai2652-png,specification-phase-exercise-controller,09/01/2026,10/16/2026,8,317,213,8,5,ai2652-png,5,5,0,5,ai2652@nyu.edu,,6,8
|
|
46
|
+
bloombar,specification-phase-exercise-controller,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
47
|
+
,specification-phase-exercise-controller,09/01/2026,10/16/2026,0,0,0,0,0,scanfasri,0,0,0,0,,,1,0
|
|
48
|
+
ShuoWu6529,specification-phase-exercise-forked,09/01/2026,10/16/2026,7,24,6,7,11,ShuoWu6529,6,6,0,4,sw6529@nyu.edu,sw6529@nyu.edu,1,0
|
|
49
|
+
bloombar,specification-phase-exercise-forked,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
50
|
+
ew2725,specification-phase-exercise-forked,09/01/2026,10/16/2026,6,24,14,6,6,ew2725,5,5,0,1,ew2725@nyu.edu,,0,0
|
|
51
|
+
jack-k-jiang,specification-phase-exercise-forked,09/01/2026,10/16/2026,8,37,14,8,6,jack-k-jiang,8,8,0,6,82908596+jack-k-jiang@users.noreply.github.com; jackj12358@gmail.com,,0,0
|
|
52
|
+
ronaldszeto,specification-phase-exercise-forked,09/01/2026,10/16/2026,7,24,3,7,1,ronaldszeto,5,5,0,1,rs9316@nyu.edu,,1,2
|
|
53
|
+
xuruikun,specification-phase-exercise-forked,09/01/2026,10/16/2026,23,93,61,23,3,xuruikun,7,7,0,7,88195416+xuruikun@users.noreply.github.com,,8,23
|
|
54
|
+
MarcoHGulino,specification-phase-exercise-team2,09/01/2026,10/16/2026,5,81,36,5,0,MarcoHGulino,0,0,0,0,mg6378@nyu.edu,,3,5
|
|
55
|
+
Sai Shettar,specification-phase-exercise-team2,09/01/2026,10/16/2026,12,46,14,12,0,saishettar,0,0,0,0,sai.r.shettar@gmail.com,saishettar@nyu.edu,4,12
|
|
56
|
+
SiennaSSM,specification-phase-exercise-team2,09/01/2026,10/16/2026,14,122,48,14,0,SiennaSSM,0,0,0,0,sm12131@nyu.edu,,4,14
|
|
57
|
+
bloombar,specification-phase-exercise-team2,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
58
|
+
elbow74,specification-phase-exercise-team2,09/01/2026,10/16/2026,5,86,48,5,0,elbow74,0,0,0,0,92692888+elbow74@users.noreply.github.com,,5,5
|
|
59
|
+
Abyssjac,specification-phase-exercise-sth,09/01/2026,10/16/2026,7,229,183,8,1,Abyssjac,0,0,0,0,131870078+Abyssjac@users.noreply.github.com; zuzhou.abyss@gmail.com,,7,0
|
|
60
|
+
Jessie Zhang,specification-phase-exercise-sth,09/01/2026,10/16/2026,7,24,10,7,0,jessiezhang218,1,1,0,1,jessiezhang0218@gmail.com; jz6102@nyu.edu,jessiezhang0218@gmail.com,1,7
|
|
61
|
+
Shiqi Wang,specification-phase-exercise-sth,09/01/2026,10/16/2026,5,132,66,5,4,ShiqiWang1115,4,4,0,4,sw6423@nyu.edu,,0,0
|
|
62
|
+
Sinu112,specification-phase-exercise-sth,09/01/2026,10/16/2026,2,74,2,2,0,Sinu112,2,2,0,2,xs2471@nyu.edu,,0,2
|
|
63
|
+
bloombar,specification-phase-exercise-sth,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
64
|
+
TracyWang0904,specification-phase-exercise-byteme,09/01/2026,10/16/2026,8,226,43,21,0,TracyWang0904,0,0,0,0,yw8252@nyu.edu,,8,0
|
|
65
|
+
bloombar,specification-phase-exercise-byteme,09/01/2026,10/16/2026,0,0,0,0,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
66
|
+
AliG643,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,4,90,9,4,4,AliG643,1,1,0,0,sg7920@nyu.edu,sg7920@nyu.edu,0,0
|
|
67
|
+
S1rius-Yang,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,1,3,1,1,0,S1rius-Yang,0,0,0,0,hy2743@nyu.edu,,0,1
|
|
68
|
+
Sirius,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,3,6,4,3,0,,0,0,0,0,s1rius@SiriusdeMacBook-Pro.local,,0,0
|
|
69
|
+
Yuyang-Ding1102,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,4,425,63,4,7,Yuyang-Ding1102,2,1,1,1,yd2734@nyu.edu,,0,4
|
|
70
|
+
Yvonne,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,2,80,27,2,0,Lyvoj,0,0,0,0,261538801+Lyvoj@users.noreply.github.com,,0,0
|
|
71
|
+
Zihan Chen,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,6,148,88,6,0,Vent1Zzz,0,0,0,0,203582969+Vent1Zzz@users.noreply.github.com,,1,0
|
|
72
|
+
bloombar,specification-phase-exercise-purple-sasquatch,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
73
|
+
Dizay-53,specification-exercise-hibiscus,09/01/2026,10/16/2026,3,46,3,3,0,Dizay-53,2,2,0,1,Ya2522@nyu.edu,,0,3
|
|
74
|
+
LefeiKe,specification-exercise-hibiscus,09/01/2026,10/16/2026,4,54,6,4,3,LefeiKe,4,4,0,1,87459566+LefeiKe@users.noreply.github.com; lk3104@nyu.edu,,0,0
|
|
75
|
+
ange285,specification-exercise-hibiscus,09/01/2026,10/16/2026,1,2,1,1,1,ange285,1,1,0,0,enjelia126@gmail.com,,0,1
|
|
76
|
+
bloombar,specification-exercise-hibiscus,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
77
|
+
sofia-matari,specification-exercise-hibiscus,09/01/2026,10/16/2026,2,46,11,2,6,sofia-matari,2,2,0,0,sbm9838@nyu.edu,,0,0
|
|
78
|
+
yasminek27,specification-exercise-hibiscus,09/01/2026,10/16/2026,9,118,28,9,5,yasminek27,9,9,0,0,yk2154@nyu.edu,,0,0
|
|
79
|
+
aw4580,specification-phase-exercise-search,09/01/2026,10/16/2026,6,57,30,6,0,aw4580,0,0,0,0,134334340+aw4580@users.noreply.github.com; aw4580@nyu.edu,,7,5
|
|
80
|
+
benzaslavsky,specification-phase-exercise-search,09/01/2026,10/16/2026,1,17,2,1,2,benzaslavsky,1,1,0,1,62486098+benzaslavsky@users.noreply.github.com; benzy.venue@gmail.com,,0,0
|
|
81
|
+
bloombar,specification-phase-exercise-search,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
82
|
+
iindes,specification-phase-exercise-search,09/01/2026,10/16/2026,1,1,1,1,1,iindes,1,1,0,1,59502115+iindes@users.noreply.github.com,,0,1
|
|
83
|
+
lkykathy,specification-phase-exercise-search,09/01/2026,10/16/2026,7,338,61,7,6,lkykathy,7,7,0,6,67247076+lkykathy@users.noreply.github.com; linkeying0425@gmail.com,,0,0
|
|
84
|
+
saramhersch,specification-phase-exercise-search,09/01/2026,10/16/2026,1,4,0,1,0,saramhersch,0,0,0,0,smh9864@nyu.edu,,1,1
|
|
85
|
+
SparkFan-ui,specification-phase-exercise-sttke,09/01/2026,10/16/2026,4,271,28,5,0,SparkFan-ui,0,0,0,0,jf4832@nyu.edu,,6,4
|
|
86
|
+
bloombar,specification-phase-exercise-sttke,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
87
|
+
kevinhan923,specification-phase-exercise-sttke,09/01/2026,10/16/2026,3,116,185,3,0,kevinhan923,0,0,0,0,69257524+kevinhan923@users.noreply.github.com,,4,0
|
|
88
|
+
23matthewc,specification-phase-exercise-nocturnal,09/01/2026,10/16/2026,0,0,0,0,2,23matthewc,0,0,0,0,76405126+23matthewc@users.noreply.github.com,,0,0
|
|
89
|
+
ajoykumarrishi,specification-phase-exercise-nocturnal,09/01/2026,10/16/2026,14,310,24,14,0,ajoykumarrishi,1,1,0,0,151567609+ajoykumarrishi@users.noreply.github.com; rishi.ajoykumar9@gmail.com,,0,14
|
|
90
|
+
bloombar,specification-phase-exercise-nocturnal,09/01/2026,10/16/2026,0,0,0,0,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
91
|
+
christinalin06,specification-phase-exercise-nocturnal,09/01/2026,10/16/2026,7,119,31,7,1,christinalin06,2,2,0,0,Christinalin006@gmail.com,,3,1
|
|
92
|
+
DyingRavioli,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,5,147,87,5,3,DyingRavioli,5,5,0,5,109256424+DyingRavioli@users.noreply.github.com,,1,5
|
|
93
|
+
RayyanAhmed21,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,4,121,17,4,0,RayyanAhmed21,0,0,0,0,ra4073@nyu.edu,,0,0
|
|
94
|
+
UIYrj,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,3,38,4,3,2,UIYrj,2,2,0,2,158982316+UIYrj@users.noreply.github.com,,0,3
|
|
95
|
+
bloombar,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,1,15,0,1,1,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
96
|
+
rz3007,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,2,54,4,2,0,rz3007,0,0,0,0,rz3007@nyu.edu,,0,2
|
|
97
|
+
sanay-d-nyu,specification-phase-exercise-goodTeam,09/01/2026,10/16/2026,6,77,9,6,1,sanay-d-nyu,1,1,0,1,sd5113@nyu.edu,sd5113@nyu.edu,1,0
|
|
98
|
+
DaniyalMl,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,1,1,0,1,0,DaniyalMlk,0,0,0,0,103329154+DaniyalMlk@users.noreply.github.com,,1,1
|
|
99
|
+
Jayyu2005,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,1,6,1,1,0,Jayyu2005,0,0,0,0,jy4886@nyu.edu,,1,1
|
|
100
|
+
LefeiKe,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,2,2,2,2,0,LefeiKe,0,0,0,0,lk3104@nyu.edu,,2,0
|
|
101
|
+
bloombar,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,1,1,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
102
|
+
catw1thtea,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,3,5,3,3,0,catw1thtea,0,0,0,0,ds7746@nyu.edu,danialsagymbayev@gmail.com,3,3
|
|
103
|
+
denisekos,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,1,129,5,1,0,denisekos,0,0,0,0,denise.koswara28@gmail.com,,1,1
|
|
104
|
+
manzim7,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,3,9,3,3,5,manzim7,0,0,0,0,mm13507@nyu.edu,,3,0
|
|
105
|
+
,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,0,0,0,0,0,mosada2515,1,0,1,0,,,0,0
|
|
106
|
+
,specification-phase-exercise-ddjz,09/01/2026,10/16/2026,0,0,0,0,0,Yded21,1,0,0,0,,,0,0
|
|
107
|
+
LefeiKe,specification-phase-exercise-team1,09/01/2026,10/16/2026,2,2,2,2,0,LefeiKe,0,0,0,0,lk3104@nyu.edu,,0,0
|
|
108
|
+
Yded21,specification-phase-exercise-team1,09/01/2026,10/16/2026,1,187,14,1,0,Yded21,1,1,0,0,eddyzzy@outlook.com,,0,1
|
|
109
|
+
ac11238,specification-phase-exercise-team1,09/01/2026,10/16/2026,9,29,12,9,0,ac11238,0,0,0,0,ac11348@nyu.edu,,12,9
|
|
110
|
+
bloombar,specification-phase-exercise-team1,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
111
|
+
manzim7,specification-phase-exercise-team1,09/01/2026,10/16/2026,1,5,1,1,0,manzim7,0,0,0,0,mm13507@nyu.edu,,0,0
|
|
112
|
+
uwtz,specification-phase-exercise-team1,09/01/2026,10/16/2026,8,189,37,8,1,uwtz,0,0,0,0,86273231+uwtz@users.noreply.github.com,,8,8
|
|
113
|
+
SeanA12,specification-phase-exercise-GitLost,09/01/2026,10/16/2026,2,36,2,2,2,SeanA12,2,2,0,0,106447402+SeanA12@users.noreply.github.com; seanalliman112@gmai.com,,0,0
|
|
114
|
+
bloombar,specification-phase-exercise-GitLost,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
115
|
+
layan-al,specification-phase-exercise-GitLost,09/01/2026,10/16/2026,4,161,5,4,0,layan-al,5,4,1,0,103759519+layan-al@users.noreply.github.com,,0,0
|
|
116
|
+
ogngnaoh,specification-phase-exercise-GitLost,09/01/2026,10/16/2026,0,0,0,0,4,ogngnaoh,0,0,0,0,ngoviethoang9@gmail.com,,0,0
|
|
117
|
+
rayyang262,specification-phase-exercise-GitLost,09/01/2026,10/16/2026,1,2,2,1,0,rayyang262,0,0,0,0,rayyang2026@gmail.com,,1,1
|
|
118
|
+
BrianDai22,specification-phase-exercise-mihir-brian-yash-linh-theo,09/01/2026,10/16/2026,3,158,157,4,0,BrianDai22,0,0,0,0,mooprules@gmail.com,,0,0
|
|
119
|
+
Mihir Ganesan,specification-phase-exercise-mihir-brian-yash-linh-theo,09/01/2026,10/16/2026,6,243,35,6,0,,0,0,0,0,mihirganesan@10-17-27-151.dynapool.wireless.nyu.edu; mihirganesan@10-17-58-124.dynapool.wireless.nyu.edu,,0,0
|
|
120
|
+
bloombar,specification-phase-exercise-mihir-brian-yash-linh-theo,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
121
|
+
theoegoldstine,specification-phase-exercise-mihir-brian-yash-linh-theo,09/01/2026,10/16/2026,4,6,4,4,0,theoegoldstine,0,0,0,0,63026703+theoegoldstine@users.noreply.github.com,,0,4
|
|
122
|
+
yash-pandya9798,specification-phase-exercise-mihir-brian-yash-linh-theo,09/01/2026,10/16/2026,1,8,2,1,0,yash-pandya9798,0,0,0,0,yash.pandya9798@gmail.com,,0,1
|
|
123
|
+
RayyanAhmed21,specification-phase-exercise,09/01/2026,10/16/2026,5,175,18,5,4,RayyanAhmed21,4,4,0,4,ra4073@nyu.edu,,0,1
|
|
124
|
+
bloombar,specification-phase-exercise,09/01/2026,10/16/2026,1,15,0,1,1,bloombar,1,1,0,1,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
125
|
+
rz3007,specification-phase-exercise,09/01/2026,10/16/2026,3,55,5,3,1,rz3007,1,1,0,1,rz3007@nyu.edu,,1,3
|
|
126
|
+
bloombar,specification-phase-exercise-helloworld,09/01/2026,10/16/2026,1,15,0,1,0,bloombar,0,0,0,0,2209098+bloombar@users.noreply.github.com; amos@cs.nyu.edu,,0,0
|
|
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gitlogstats"
|
|
7
7
|
description = "Track developers' contributions to one or more git repositories within a particular time range."
|
|
8
|
-
version = "1.
|
|
8
|
+
version = "1.6.0"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name="Tobody Tothing", email="nobody.nothing@nowhere.com" },
|
|
11
11
|
]
|
|
@@ -132,6 +132,22 @@
|
|
|
132
132
|
family: OUT
|
|
133
133
|
phase: 1
|
|
134
134
|
status: Done
|
|
135
|
+
- id: OUT-6
|
|
136
|
+
title: Aggregated results
|
|
137
|
+
full: -a/--aggregate developer prints one row per developer, summed over every
|
|
138
|
+
repository analyzed, instead of one row per contributor per repository. Its
|
|
139
|
+
columns are username, start_date, end_date, commits, insertions, deletions,
|
|
140
|
+
files, merges, repositories, where repositories is the number of
|
|
141
|
+
repositories in which the developer has any activity in the date range (a
|
|
142
|
+
non-zero count, git or GitHub, as for -c); there is no repository column.
|
|
143
|
+
With --github, the columns github_username, prs_opened, prs_merged,
|
|
144
|
+
prs_closed_unmerged, prs_self_merged, git_email, github_email,
|
|
145
|
+
pushes_to_default, web_commits follow. Rows are combined when they share a
|
|
146
|
+
GitHub username (ignoring case), or, for rows without…
|
|
147
|
+
section: §4 Output
|
|
148
|
+
family: OUT
|
|
149
|
+
phase: 1
|
|
150
|
+
status: Done
|
|
135
151
|
- id: PKG-1
|
|
136
152
|
title: Installable package
|
|
137
153
|
full: The tool installs with pip install gitlogstats, which provides a
|
|
@@ -5,6 +5,7 @@ import datetime
|
|
|
5
5
|
import re
|
|
6
6
|
import sys
|
|
7
7
|
from . import GitLogsParser
|
|
8
|
+
from . import aggregate
|
|
8
9
|
from .clones import remove_clones
|
|
9
10
|
from .git_logs_parser import FIELDNAMES
|
|
10
11
|
from .github import (
|
|
@@ -146,6 +147,14 @@ def main():
|
|
|
146
147
|
default=False,
|
|
147
148
|
action="store_true",
|
|
148
149
|
)
|
|
150
|
+
parser.add_argument(
|
|
151
|
+
"-a",
|
|
152
|
+
"--aggregate",
|
|
153
|
+
help="Combine the results into one row per developer, summed over all "
|
|
154
|
+
"repositories, or one row per repository, summed over its contributors",
|
|
155
|
+
default=None,
|
|
156
|
+
choices=aggregate.MODES,
|
|
157
|
+
)
|
|
149
158
|
parser.add_argument(
|
|
150
159
|
"--github",
|
|
151
160
|
help="Also report GitHub pull requests opened, merged, closed and "
|
|
@@ -253,12 +262,17 @@ def main():
|
|
|
253
262
|
|
|
254
263
|
# emit a single table (or JSON array) covering all repositories
|
|
255
264
|
if last_parser is not None:
|
|
256
|
-
# an empty CSV table still gets the
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
265
|
+
# an empty CSV table still gets the columns it would have had
|
|
266
|
+
if args.aggregate:
|
|
267
|
+
# OUT-6: one row per developer or per repository
|
|
268
|
+
all_results = aggregate.aggregate(all_results, args.aggregate, args.github)
|
|
269
|
+
fieldnames = aggregate.fieldnames(args.aggregate, args.github)
|
|
270
|
+
elif args.github:
|
|
271
|
+
fieldnames = (
|
|
272
|
+
FIELDNAMES + GITHUB_FIELDNAMES + EMAIL_FIELDNAMES + ACTIVITY_FIELDNAMES
|
|
273
|
+
)
|
|
274
|
+
else:
|
|
275
|
+
fieldnames = None
|
|
262
276
|
output = last_parser.format_results(all_results, args.format, fieldnames)
|
|
263
277
|
# end with exactly one newline: CSV and Markdown output already has one
|
|
264
278
|
print(output, end="" if output.endswith("\n") else "\n")
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Combine result rows by developer or by repository (OUT-6).
|
|
2
|
+
|
|
3
|
+
Everything here is pure logic over the rows the rest of the tool produces: no
|
|
4
|
+
git, no network. Each aggregated row sums the counts of the rows it combines.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from gitlogstats.git_logs_parser import FIELDNAMES
|
|
8
|
+
from gitlogstats.github import (
|
|
9
|
+
ACTIVITY_FIELDNAMES,
|
|
10
|
+
EMAIL_FIELDNAMES,
|
|
11
|
+
GITHUB_FIELDNAMES,
|
|
12
|
+
)
|
|
13
|
+
from gitlogstats.identity import join_emails
|
|
14
|
+
|
|
15
|
+
DEVELOPER = "developer"
|
|
16
|
+
REPOSITORY = "repository"
|
|
17
|
+
MODES = [DEVELOPER, REPOSITORY]
|
|
18
|
+
|
|
19
|
+
# the git counts (commits to merges), summed in both modes
|
|
20
|
+
GIT_COUNTS = FIELDNAMES[4:]
|
|
21
|
+
|
|
22
|
+
# the GitHub pull-request counts (CLI-3), summed in both modes
|
|
23
|
+
PR_COUNTS = GITHUB_FIELDNAMES[1:]
|
|
24
|
+
|
|
25
|
+
# every count; a row with any of them non-zero is active, as for -c (FILT-4)
|
|
26
|
+
ALL_COUNTS = GIT_COUNTS + PR_COUNTS + ACTIVITY_FIELDNAMES
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def fieldnames(mode, github):
|
|
30
|
+
"""
|
|
31
|
+
The output columns of an aggregated table, in order.
|
|
32
|
+
@param mode: DEVELOPER or REPOSITORY
|
|
33
|
+
@param github: whether the GitHub columns are reported (--github)
|
|
34
|
+
@returns: a list of column names
|
|
35
|
+
"""
|
|
36
|
+
dates = ["start_date", "end_date"]
|
|
37
|
+
if mode == DEVELOPER:
|
|
38
|
+
columns = ["username"] + dates + GIT_COUNTS + ["repositories"]
|
|
39
|
+
if github:
|
|
40
|
+
columns += ["github_username"] + PR_COUNTS + EMAIL_FIELDNAMES
|
|
41
|
+
columns += ACTIVITY_FIELDNAMES
|
|
42
|
+
else:
|
|
43
|
+
columns = ["repository"] + dates + GIT_COUNTS + ["contributors"]
|
|
44
|
+
if github:
|
|
45
|
+
columns += PR_COUNTS + ACTIVITY_FIELDNAMES
|
|
46
|
+
return columns
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def developer_key(row):
|
|
50
|
+
"""
|
|
51
|
+
The developer a row belongs to: its GitHub user, ignoring case, when it
|
|
52
|
+
has one, otherwise its exact git username.
|
|
53
|
+
@param row: a result row
|
|
54
|
+
@returns: a hashable key
|
|
55
|
+
"""
|
|
56
|
+
login = row.get("github_username")
|
|
57
|
+
if login:
|
|
58
|
+
return ("github", login.casefold())
|
|
59
|
+
return ("git", row["username"])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def is_active(row):
|
|
63
|
+
"""
|
|
64
|
+
Whether a row has any activity: a non-zero count, git or GitHub.
|
|
65
|
+
@param row: a result row
|
|
66
|
+
@returns: a bool
|
|
67
|
+
"""
|
|
68
|
+
return any(row.get(field) for field in ALL_COUNTS)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def main_username(rows):
|
|
72
|
+
"""
|
|
73
|
+
The git username of a developer's rows: the one with the most commits,
|
|
74
|
+
ties alphabetical, as when combining identities in one repository (STAT-11).
|
|
75
|
+
@param rows: the rows of one developer
|
|
76
|
+
@returns: a username, or "" if every row is GitHub-only
|
|
77
|
+
"""
|
|
78
|
+
named = [row for row in rows if row["username"]]
|
|
79
|
+
if not named:
|
|
80
|
+
return ""
|
|
81
|
+
return min(named, key=lambda row: (-(row["commits"] or 0), row["username"]))[
|
|
82
|
+
"username"
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def sum_values(values):
|
|
87
|
+
"""
|
|
88
|
+
Add up counts. An unavailable count (None, CLI-3) is skipped, so the total
|
|
89
|
+
is None only when every count is unavailable.
|
|
90
|
+
@param values: numbers or None
|
|
91
|
+
@returns: their sum, or None
|
|
92
|
+
"""
|
|
93
|
+
present = [value for value in values if value is not None]
|
|
94
|
+
return sum(present) if present else None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def first_text(values):
|
|
98
|
+
"""
|
|
99
|
+
The first non-empty text. When there is none, "" if any value is
|
|
100
|
+
available, or None if every value is unavailable.
|
|
101
|
+
@param values: strings or None
|
|
102
|
+
@returns: a string, or None
|
|
103
|
+
"""
|
|
104
|
+
values = list(values)
|
|
105
|
+
for value in values:
|
|
106
|
+
if value:
|
|
107
|
+
return value
|
|
108
|
+
return None if all(value is None for value in values) else ""
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def merge_emails(values):
|
|
112
|
+
"""
|
|
113
|
+
Join '; '-separated email lists into one sorted list without repeats
|
|
114
|
+
(STAT-13), or None if every list is unavailable.
|
|
115
|
+
@param values: '; '-separated strings, "" or None
|
|
116
|
+
@returns: a '; '-separated string, or None
|
|
117
|
+
"""
|
|
118
|
+
values = list(values)
|
|
119
|
+
if all(value is None for value in values):
|
|
120
|
+
return None
|
|
121
|
+
return join_emails(
|
|
122
|
+
email for value in values if value for email in value.split("; ")
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def combine(rows, columns):
|
|
127
|
+
"""
|
|
128
|
+
Build the aggregated row of one group.
|
|
129
|
+
@param rows: the rows of one developer or one repository
|
|
130
|
+
@param columns: the output columns, from fieldnames()
|
|
131
|
+
@returns: one row with those columns
|
|
132
|
+
"""
|
|
133
|
+
active = [row for row in rows if is_active(row)]
|
|
134
|
+
out = {}
|
|
135
|
+
for field in columns:
|
|
136
|
+
if field == "username":
|
|
137
|
+
out[field] = main_username(rows)
|
|
138
|
+
elif field in ("repository", "start_date", "end_date"):
|
|
139
|
+
out[field] = rows[0][field]
|
|
140
|
+
elif field == "repositories":
|
|
141
|
+
out[field] = len({row["repository"] for row in active})
|
|
142
|
+
elif field == "contributors":
|
|
143
|
+
out[field] = len(active)
|
|
144
|
+
elif field == "github_username":
|
|
145
|
+
out[field] = first_text(row[field] for row in rows)
|
|
146
|
+
elif field in EMAIL_FIELDNAMES:
|
|
147
|
+
out[field] = merge_emails(row[field] for row in rows)
|
|
148
|
+
else:
|
|
149
|
+
out[field] = sum_values(row[field] for row in rows)
|
|
150
|
+
return out
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def aggregate(rows, mode, github):
|
|
154
|
+
"""
|
|
155
|
+
Combine result rows into one row per developer or one row per repository,
|
|
156
|
+
sorted by username (or GitHub username, for a developer with no git
|
|
157
|
+
username) or by repository, ignoring case.
|
|
158
|
+
@param rows: result rows of every repository, after -u and -c
|
|
159
|
+
@param mode: DEVELOPER or REPOSITORY
|
|
160
|
+
@param github: whether the rows carry the GitHub columns (--github)
|
|
161
|
+
@returns: the aggregated rows, sorted
|
|
162
|
+
"""
|
|
163
|
+
groups = {}
|
|
164
|
+
for row in rows:
|
|
165
|
+
key = developer_key(row) if mode == DEVELOPER else row["repository"]
|
|
166
|
+
groups.setdefault(key, []).append(row)
|
|
167
|
+
columns = fieldnames(mode, github)
|
|
168
|
+
combined = [combine(group, columns) for group in groups.values()]
|
|
169
|
+
|
|
170
|
+
def sort_key(row):
|
|
171
|
+
if mode == DEVELOPER:
|
|
172
|
+
name = row["username"] or row.get("github_username") or ""
|
|
173
|
+
else:
|
|
174
|
+
name = row["repository"]
|
|
175
|
+
return (name.casefold(), name)
|
|
176
|
+
|
|
177
|
+
return sorted(combined, key=sort_key)
|