上次写了个 GitLab 代码统计的脚本,但是手动统计太麻烦了于是改成了自动统计(建议丢到服务器上跑),并且支持钉钉群推送(需要在钉钉群加个机器人,并获取对应的 token),不过统计这玩意儿参考价值不大。
项目地址
脚本已上传 GitHub,下方为旧版脚本,新版请前往 GitHub 获取哦~
安装依赖模块
pip3 install python-dateutil
使用方法
将脚本中的第 14-17 行修改为你自己的内容,上传到服务器即可,执行方式如下
# 统计当天
python 脚本文件.py day
# 统计本周
python 脚本文件.py week
# 统计本月
python 脚本文件.py month
可以加到 crontab 任务中,实现定时自动统计推送,例:
# 代码统计
10 19 * * 1-6 bash /root/GitLab/run.sh day
40 20 * * 1-6 bash /root/GitLab/run.sh day
00 21 * * 6 bash /root/GitLab/run.sh week
40 23 1 1-12 * bash /root/GitLab/run.sh month
注意事项
Git 用户名不是指 GitLab 用户名,而是 Git 提交工具配置的用户名
脚本源码
#!/usr/bin/python3
# coding=utf8
# @Author: Kinoko
# @Date : 2020/12/04
# @Desc : GitLab 按时间查看各用户代码提交量官方API版(钉钉推送版)
import sys
import json
import time
import requests
from dateutil.parser import parse
# 需修改如下四条信息
gitlab_url = "http://localhost/" # GitLab 地址
private_token = "xxxxxxxx" # GitLab Access Tokens(管理员权限)
report_path = "/root" # 生成的报告文件存放目录
dingding_token = "xxxxxxxx" # 钉钉机器人token
info_master = []
info_other = []
statistics = {}
date_key = sys.argv[1] # 获取传入的第一个参数:week,month,day
headers = {
'Connection': 'close',
}
# UTC时间转时间戳
def utc_time(time):
dt = parse(time)
return int(dt.timestamp())
# 获取 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:
print(project["namespace"]["name"] + " ID:" + str(project["id"]) + " 描述:" + project["description"])
project_ids.append(project["id"])
page += 1
print("共获取到 " + str(len(project_ids)) + " 个有效项目")
return project_ids
# 获取 GitLab 上的项目 id 中的分支
def project_branches(project_id):
branch_names = []
page = 1
while True:
url = gitlab_url + "api/v4/projects/" + str(
project_id) + "/repository/branches?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
branches = json.loads(res.text)
'''Debug
print(url)
print('--' * 10)
print(branches)
print('*' * 10)
'''
if len(branches) == 0:
break
else:
for branch in branches:
branch_names.append(branch["name"])
page += 1
return branch_names
# 获取 GitLab 上的项目分支中的 commits,当 title 或 message 首单词为 Merge 时,表示合并操作,剔除此代码量
def project_commits(project_id, branch, start_time, end_time):
commit_ids = []
page = 1
while True:
url = gitlab_url + "api/v4/projects/" + str(
project_id) + "/repository/commits?ref_name=" + branch + "&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
commits = json.loads(res.text)
if len(commits) == 0:
break
else:
for commit in commits:
if "Merge" in commit["title"] or "Merge" in commit["message"] or "合并" in commit["title"] or "合并" in \
commit["message"]: # 不统计合并操作
continue
elif utc_time(commit["authored_date"]) < start_time or utc_time(
commit["authored_date"]) > end_time: # 不满足时间区间
continue
else:
commit_ids.append(commit["id"])
page += 1
return commit_ids
# 根据 commits 的 id 获取代码量,type: 1 为主分支,2为其他分支
def commit_code(project_id, commit_id, branch_type):
global info_master, info_other
url = gitlab_url + "api/v4/projects/" + str(
project_id) + "/repository/commits/" + commit_id + "?private_token=" + private_token
while True:
try:
res = requests.get(url, headers=headers, timeout=10)
break
except Exception as e:
print(e)
continue
data = json.loads(res.text)
if branch_type == 1:
obj = {"name": data["author_name"], "additions": data["stats"]["additions"],
"deletions": data["stats"]["deletions"], "total": data["stats"]["total"]} # Git工具用户名,新增代码数,删除代码数,总计代码数
info_master.append(obj)
elif branch_type == 2:
obj = {"name": data["author_name"], "additions": data["stats"]["additions"],
"deletions": data["stats"]["deletions"], "total": data["stats"]["total"]} # Git工具用户名,新增代码数,删除代码数,总计代码数
info_other.append(obj)
# else:
# do some things
# GitLab 数据查询
def gitlab_info(start_time, end_time):
for project_id in gitlab_projects(): # 遍历所有项目ID
for branch_name in project_branches(project_id): # 遍历每个项目中的分支
if branch_name == "master": # 主分支
for commit_id in project_commits(project_id, branch_name, start_time, end_time): # 遍历每个分支中的 commit id
commit_code(project_id, commit_id, 1) # 获取代码提交量
else: # 其他分支
for commit_id in project_commits(project_id, branch_name, start_time, end_time):
commit_code(project_id, commit_id, 2) # 获取代码提交量
# 统计数据处理
def gitlab_statistics_data(branch_type):
global statistics
statistics.clear()
name = [] # Git工具用户名
additions = [] # 新增代码数
deletions = [] # 删除代码数
total = [] # 总计代码数
times = [] # 提交次数
if branch_type == 1:
info = info_master
elif branch_type == 2:
info = info_other
# else
# do some things
for i in info:
for key, value in i.items():
if key == "name":
name.append(value)
if key == "additions":
additions.append(value)
if key == "deletions":
deletions.append(value)
if key == "total":
total.append(value)
times.append(1) # 提交次数
array = list(zip(name, additions, deletions, total, times))
# print(array)
# 去重累加
for j in array:
name = j[0]
additions = j[1]
deletions = j[2]
total = j[3]
times = j[4]
if name in statistics.keys():
statistics[name][0] += additions
statistics[name][1] += deletions
statistics[name][2] += total
statistics[name][3] += times
else:
statistics.update({name: [additions, deletions, total, times]})
# else:
# do some things
# 代码统计内容列表处理
def gitlab_statistics_content():
for i in statistics.keys():
content_save("<tr><td>" + str(i) + "</td><td>" + str(statistics[i][0]) + "</td><td>" + str(
statistics[i][1]) + "</td><td>" + str(statistics[i][2]) + "</td><td>" + str(
statistics[i][3]) + "</td></tr>", "a")
# 保存数据到文件
def content_save(data, mode):
file = open(report_path + "/" + file_name, mode, encoding='utf-8')
file.write(data)
file.close()
# 钉钉通知
def dingding(mes):
content = {
"msgtype": "actionCard",
"actionCard": {
"title": "GitLab代码提交量统计",
"text": "![](" + imgurl + ")GitLab代码提交量统计",
"hideAvatar": "0",
"btnOrientation": "0",
"singleTitle": "点击查看详情",
"singleURL": mes
}
}
json_headers = {'Content-Type': 'application/json;charset=utf-8'}
result = requests.post("https://oapi.dingtalk.com/robot/send?access_token=" + dingding_token, json.dumps(content),
headers=json_headers).text
print(result)
if __name__ == "__main__":
print("正在统计数据,请耐心等待,这将花费不少时间~")
print(date_key)
now_time = time.time() # 获取当前所在时间戳
if date_key == "week": # 周
file_name = "week.html"
imgurl = "https://ae01.alicdn.com/kf/U2a5dbe53da1a442ea8fdc54cb511dfefM.jpg"
gitlab_info(now_time - 511200, now_time) # 起-止时间(时间戳)
elif date_key == "month": # 月
file_name = "month.html"
imgurl = "https://ae01.alicdn.com/kf/U7f01e81b945b4069864be36843c6a0f8I.jpg"
gitlab_info(int(utc_time(time.strftime("%Y-%m-01 00:00:00"))), now_time)
elif date_key == "day": # 天
file_name = "day.html"
imgurl = "https://ae01.alicdn.com/kf/U56b2fb24ff7b4e5fa05c5acf7d3d0318r.jpg"
gitlab_info(int(utc_time(time.strftime("%Y-%m-%d 00:00:00"))), now_time)
else:
print("您的参数错误!")
sys.exit(1)
# 保存结果
# header
content_save(
"<!DOCTYPE html><html><head><title>GitLab代码提交量统计</title><meta charset=\"utf-8\"/><link href=\"https://cdn.jsdelivr.net/gh/Fog-Forest/[email protected]/markdown/markdown.css\" rel=\"stylesheet\" type=\"text/css\" /></head><body><h3>GitLab代码提交量统计(单位:行) TAG:" + date_key + "</h3><h5>上次更新时间:" + time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime()) + "</h5><br><blockquote><p>master</p></blockquote><table><thead><tr><th>Git用户名</th><th>新增代码数</th><th>删除代码数</th><th>总计代码数</th><th>提交次数</th></tr></thead><tbody>",
"w")
# content
gitlab_statistics_data(1) # 主分支
gitlab_statistics_content()
content_save(
"</tbody></table><blockquote><p>dev</p></blockquote><table><thead><tr><th>Git用户名</th><th>新增代码数</th><th>删除代码数</th><th>总计代码数</th><th>提交次数</th></tr></thead><tbody>",
"a")
gitlab_statistics_data(2) # 其他分支
gitlab_statistics_content()
# floor
content_save("</tbody></table></body></html>", "a")
# dingding("http://www.baidu.com/" + date_key + ".html") # 填写生成的 html 文件链接,不需要推送可以注释掉
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + " OK~")
Comments | 1 条评论
博主 dqzboy
大佬。我执行最后报错了
TypeError: string indices must be integers