[sysadmin-bin] Add script for generating GitLab activity report



commit f3fd7723082fcd5070319685f33c11b05b38f974
Author: Bartłomiej Piotrowski <bpiotrowski gnome org>
Date:   Fri May 15 21:54:40 2020 +0200

    Add script for generating GitLab activity report

 gitlab/activity-report | 188 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 188 insertions(+)
---
diff --git a/gitlab/activity-report b/gitlab/activity-report
new file mode 100644
index 0000000..7c45afe
--- /dev/null
+++ b/gitlab/activity-report
@@ -0,0 +1,188 @@
+#!/usr/bin/python3
+
+import argparse
+import json
+import os
+from collections import defaultdict
+from datetime import datetime
+
+import gitlab  # type: ignore
+
+
+def get_stats(gl, args):
+    group = gl.groups.get(8, with_projects=False, lazy=True)
+    projects = [
+        gl.projects.get(prj.id) for prj in group.projects.list(all=True, lazy=True)
+    ]
+
+    users = defaultdict(lambda: defaultdict(int))
+    since_dt = datetime.strptime(args.since, "%Y-%m-%d")
+    until_dt = datetime.strptime(args.until, "%Y-%m-%d")
+
+    projects_len = len(projects)
+    for count, proj in enumerate(projects):
+        print(f"=> Processing project {proj.id} ({count}/{projects_len})")
+
+        issues_enabled = proj.attributes["issues_enabled"]
+        mrs_enabled = proj.attributes["merge_requests_enabled"]
+
+        if issues_enabled:
+            created_issues = set(
+                proj.issues.list(
+                    created_after=args.since, created_before=args.until, all=True
+                )
+            )
+
+            updated_issues = (
+                set(
+                    proj.issues.list(
+                        updated_after=args.since,
+                        updated_before=args.until,
+                        state="closed",
+                        all=True,
+                    )
+                )
+                - created_issues
+            )
+
+            for issue in created_issues | updated_issues:
+                print(f":: issue {issue.id}")
+                created_at = issue.attributes["created_at"]
+                created_at_dt = datetime.strptime(created_at[0:10], "%Y-%m-%d")
+
+                closed_at = issue.attributes["closed_at"]
+                if closed_at:
+                    closed_at_dt = datetime.strptime(closed_at[0:10], "%Y-%m-%d")
+
+                    if not (until_dt >= closed_at_dt >= since_dt):
+                        continue
+
+                if until_dt >= created_at_dt >= since_dt:
+                    author = issue.attributes["author"]
+                    author_id = author["id"]
+                    users[author_id]["opened_issues"] += 1
+
+                closed_by = issue.attributes["closed_by"]
+                if closed_by:
+                    closed_by_id = closed_by["id"]
+                    users[closed_by_id]["closed_issues"] += 1
+
+        if mrs_enabled:
+            created_mrs = set(
+                proj.mergerequests.list(
+                    created_after=args.since, created_before=args.until, all=True
+                )
+            )
+
+            updated_mrs = (
+                set(
+                    proj.mergerequests.list(
+                        updated_after=args.since,
+                        updated_before=args.until,
+                        state="merged",
+                        all=True,
+                    )
+                )
+                - created_mrs
+            )
+
+            for mr in created_mrs | updated_mrs:
+                print(f":: merge request {mr.id}")
+
+                created_at = mr.attributes["created_at"]
+                created_at_dt = datetime.strptime(created_at[0:10], "%Y-%m-%d")
+
+                merged_at = mr.attributes["merged_at"]
+                if merged_at:
+                    merged_at_dt = datetime.strptime(merged_at[0:10], "%Y-%m-%d")
+
+                    if not (until_dt >= merged_at_dt >= since_dt):
+                        continue
+
+                if until_dt >= created_at_dt >= since_dt:
+                    author = mr.attributes["author"]
+                    author_id = author["id"]
+                    users[author_id]["opened_mr"] += 1
+
+                # Comments are saved internally as "notes"
+                notes = mr.notes.list(all=True)
+
+                if merged_at:
+                    merged_by = mr.attributes["merged_by"]
+                    if merged_by:
+                        merged_by_id = merged_by["id"]
+                    else:
+                        # GitLab returns "None" for some MRs, so fetch the info form
+                        # notes
+                        for note in notes:
+                            attrs = note.attributes
+                            if attrs["system"] and attrs["body"] == "merged":
+                                merged_by_id = attrs["author"]["id"]
+                                break
+
+                    users[merged_by_id]["merged_mrs"] += 1
+
+                for note in notes:
+                    if note.attributes["system"]:
+                        continue
+
+                    attrs = note.attributes
+                    note_created_at = attrs["created_at"]
+                    note_created_at_dt = datetime.strptime(
+                        note_created_at[0:10], "%Y-%m-%d"
+                    )
+
+                    if until_dt >= note_created_at_dt >= since_dt:
+                        comment_author_id = attrs["author"]["id"]
+                        users[comment_author_id]["mr_comments"] += 1
+
+    return users
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description="Generate GitLab usage statistics")
+    parser.add_argument("--since", type=str, required=True)
+    parser.add_argument("--until", type=str, required=True)
+    parser.add_argument("--token", type=str)
+    args = parser.parse_args()
+
+    gl = gitlab.Gitlab(
+        "https://gitlab.gnome.org";, private_token=args.token, per_page=100
+    )
+    gl.auth()
+
+    filename = f"gitlabstats-{args.since}_{args.until}.json"
+    if os.path.exists(filename):
+        with open(filename) as f:
+            stats = json.load(f)
+    else:
+        stats = get_stats(gl, args)
+        with open(filename, "w") as f:
+            json.dump(stats, f)
+
+    users_ids = list(stats.keys())
+    group = gl.groups.get(8, with_projects=False, lazy=True)
+    members_ids = [user.id for user in group.members.list(all=True, lazy=True)]
+
+    metrics = [
+        "opened_issues",
+        "closed_issues",
+        "opened_mr",
+        "merged_mrs",
+        "mr_comments",
+    ]
+
+    for metric in metrics:
+        total = sum(stats[x].get(metric, 0) for x in stats)
+        top = sorted(users_ids, key=lambda x: stats[x].get(metric, 0), reverse=True)[
+            0:10
+        ]
+
+        print(f"=> {metric}_total: {total}")
+        for user_id in top:
+            user = gl.users.get(user_id)
+            name = user.attributes["name"]
+            is_gnome_member = "*" if user.id not in members_ids else ""
+
+            print(f"{stats[user_id][metric]} {name}{is_gnome_member}")
+        print("")


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]