今天接到主管命令,需要统计每个人每月的代码提交量,纳入每月的绩效考核(神奇的需求)。虽然可以通过查看 GitLab 上每个人的提交记录来统计,但是费时费力,所以这里通过脚本的方式来统计。
注意:GitLab 的 API 请求得到的数据会自动分页,网上很多教程都没有说明,导致统计出来的数据有误

准备

  1. GitLab 地址(内网外网都可以,内网需要在内网中执行脚本)
  2. 拥有 GitLab 管理权限的用户账号
  3. Python 3 环境

    逻辑

  4. 首先遍历所有项目

  5. 然后遍历所有项目下拥有的所有分支
  6. 遍历所有分支下每个用户提交的代码量
  7. 时间区间限制
  8. 数据去重相加,格式化输出

    脚本

  9. 登录 GitLab,选择 设置 - Access Tokens,创建个人访问令牌
    image.png
    image.png

  10. 复制生成的个人访问令牌到脚本的 private_token 中,再将 url 改为你的 GitLab 地址,最后修改 起-止时间 执行脚本即可
  11. 脚本,基于 GitLab 官方 API,注意 Git用户名 是提交工具上配置的名字,不是 GitLab 用户名 ```python

    !/usr/bin/python3

    coding=utf8

    @Author: Mario

    @Date : 2020/11/04

    @Desc : GitLab 按时间查看各用户代码提交量官方API版

import json import requests from dateutil.parser import parse

gitlab_url = “http://gitlab.xxxx“ # GitLab 地址 private_token = “token” # GitLab Access Tokens(管理员权限)

info = []

headers = { ‘Connection’: ‘close’, }

UTC时间转时间戳

def utc_time(time): dt = parse(time) return int(dt.timestamp())

输出格式化

def str_format(txt): lenTxt = len(txt) lenTxt_utf8 = len(txt.encode(‘utf-8’)) size = int((lenTxt_utf8 - lenTxt) / 2 + lenTxt) length = 20 - size return length

获取 GitLab 上的所有项目

def gitlab_projects(): project_ids = [] page = 1 while True: url = gitlab_url + “api/v4/projects/?private_token=” + private_token + “&page=” + str(page) + “&per_page=20” while True: try: res = requests.get(url, headers=headers, timeout=10) break except Exception as e: print(e) continue projects = json.loads(res.text) if len(projects) == 0: break else: for project in projects: project_ids.append(project[“id”]) page += 1 return project_ids

  1. # 获取 GitLab 上的项目 id 中的分支
  2. def project_branches(project_id):
  3. branch_names = []
  4. page = 1
  5. while True:
  6. url = gitlab_url + "api/v4/projects/" + str(
  7. project_id) + "/repository/branches?private_token=" + private_token + "&page=" + str(page) + "&per_page=20"
  8. while True:
  9. try:
  10. res = requests.get(url, headers=headers, timeout=10)
  11. break
  12. except Exception as e:
  13. print(e)
  14. continue
  15. branches = json.loads(res.text)
  16. '''Debug
  17. print(url)
  18. print('--' * 10)
  19. print(branches)
  20. print('*' * 10)
  21. '''
  22. if len(branches) == 0:
  23. break
  24. else:
  25. for branch in branches:
  26. branch_names.append(branch["name"])
  27. page += 1
  28. return branch_names
  29. # 获取 GitLab 上的项目分支中的 commits,当 title 或 message 首单词为 Merge 时,表示合并操作,剔除此代码量
  30. def project_commits(project_id, branch, start_time, end_time):
  31. commit_ids = []
  32. page = 1
  33. while True:
  34. url = gitlab_url + "api/v4/projects/" + str(
  35. project_id) + "/repository/commits?ref_name=" + branch + "&private_token=" + private_token + "&page=" + str(
  36. page) + "&per_page=20"
  37. while True:
  38. try:
  39. res = requests.get(url, headers=headers, timeout=10)
  40. break
  41. except Exception as e:
  42. print(e)
  43. continue
  44. commits = json.loads(res.text)
  45. if len(commits) == 0:
  46. break
  47. else:
  48. for commit in commits:
  49. if "Merge" in commit["title"] or "Merge" in commit["message"] or "合并" in commit["title"] or "合并" in \
  50. commit["message"]: # 不统计合并操作
  51. continue
  52. elif utc_time(commit["authored_date"]) < utc_time(start_time) or utc_time(
  53. commit["authored_date"]) > utc_time(end_time): # 不满足时间区间
  54. continue
  55. else:
  56. commit_ids.append(commit["id"])
  57. page += 1
  58. return commit_ids
  59. # 根据 commits 的 id 获取代码量
  60. def commit_code(project_id, commit_id):
  61. global info
  62. url = gitlab_url + "api/v4/projects/" + str(
  63. project_id) + "/repository/commits/" + commit_id + "?private_token=" + private_token
  64. while True:
  65. try:
  66. res = requests.get(url, headers=headers, timeout=10)
  67. break
  68. except Exception as e:
  69. print(e)
  70. continue
  71. data = json.loads(res.text)
  72. temp = {"name": data["author_name"], "additions": data["stats"]["additions"],
  73. "deletions": data["stats"]["deletions"], "total": data["stats"]["total"]} # Git工具用户名,新增代码数,删除代码数,总计代码数
  74. info.append(temp)
  75. # GitLab 数据查询
  76. def gitlab_info(start_time, end_time):
  77. for project_id in gitlab_projects(): # 遍历所有项目ID
  78. for branche_name in project_branches(project_id): # 遍历每个项目中的分支
  79. for commit_id in project_commits(project_id, branche_name, start_time, end_time): # 遍历每个分支中的 commit id
  80. commit_code(project_id, commit_id) # 获取代码提交量
  81. if __name__ == "__main__":
  82. print("正在统计数据,请耐心等待,这将花费不少时间~")
  83. gitlab_info('2020-12-01 00:00:00', '2020-12-01 23:59:59') # 起-止时间
  84. name = [] # Git工具用户名
  85. additions = [] # 新增代码数
  86. deletions = [] # 删除代码数
  87. total = [] # 总计代码数
  88. res = {}
  89. # 生成元组
  90. for i in info:
  91. for key, value in i.items():
  92. if key == "name":
  93. name.append(value)
  94. if key == "additions":
  95. additions.append(value)
  96. if key == "deletions":
  97. deletions.append(value)
  98. if key == "total":
  99. total.append(value)
  100. data = list(zip(name, additions, deletions, total))
  101. # print(data)
  102. # 去重累加
  103. for j in data:
  104. name = j[0]
  105. additions = j[1]
  106. deletions = j[2]
  107. total = j[3]
  108. if name in res.keys():
  109. res[name][0] += additions
  110. res[name][1] += deletions
  111. res[name][2] += total
  112. else:
  113. res.update({name: [additions, deletions, total]})
  114. # 打印结果
  115. print("Git用户名 新增代码数 删除代码数 总计代码数")
  116. for k in res.keys():
  117. print(k + " " * str_format(k) + str(res[k][0]) + " " * str_format(str(res[k][0])) + str(
  118. res[k][1]) + " " * str_format(str(res[k][1])) + str(res[k][2]))

```

结果

image.png
参考:怎么统计公司Gitlab上每个人每天的提交量