GitLab代码库提交量统计工具

1.说明

统计公司所有项目的提交情况,可指定分支和时间段,返回每个人的提交新增数、删除数和总数。

2.API

文档地址:http://公司gitlab域名/help/api/README.md

  • 项目列表查询

    返回示例:
json 复制代码
[
    {
        "id": 1, //项目ID
        "http_url_to_repo": "http://git.xxx.com/a/saas-project-1.git",
        "web_url": "http://git.xxx.com/a/saas-project-1",
        "name": "saas-project-1", //项目名
        "name_with_namespace": "a / saas-project-1",
        "path": "saas-project-1",
        "path_with_namespace": "a/saas-project-1"
    }
]
  • 提交记录查询
  • 单次提交统计
3.PRIVATE-TOKEN

PRIVATE-TOKEN获取地址:http://公司gitlab域名/profile/account

查看Private token下面的值即可

4.代码
java 复制代码
package com.visy.utils;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.tuple.Triple;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author visy.wang
 */
public class GitStatsUtil {
    private static final String PRIVATE_TOKEN = "你自己的Private token";
    private static final String BASE_URL = "http://公司gitlab域名/api/v4";

    private static <T> T doGet(String url, Function<String,T> respHandler, Supplier<T> defaultResp){
        HttpRequest request = HttpUtil.createGet(BASE_URL + url);
        request.header("PRIVATE-TOKEN", PRIVATE_TOKEN);
        HttpResponse response = request.execute();
        if(response.getStatus() == 200){
            return respHandler.apply(response.body());
        }else{
            return defaultResp.get();
        }
    }


    private static List<Map<String,Object>> listProjects(){
        int pageNo = 1, pageSize = 100;
        List<Map<String,Object>> allList = new ArrayList<>();
        boolean hasNext = true;
        while (hasNext){
            System.out.println("listProjects: pageNo=" + pageNo);
            List<Map<String,Object>> list = listProjects(pageNo, pageSize);
            allList.addAll(list);
            pageNo ++;
            hasNext = list.size() >= pageSize;
        }
        return allList;
    }

    private static List<Map<String,Object>> listProjects(int pageNo, int pageSize){
        String url = "/projects?order_by=name&sort=asc&simple=true&archived=false&owned=false&page="+pageNo+"&per_page="+pageSize;
        return doGet(url, body -> {
            JSONArray array = JSONArray.parseArray(body);
            return array.stream().map(item -> {
                Map<String,Object> mp = new HashMap<>();
                mp.put("id", ((JSONObject)item).getLong("id"));
                mp.put("name", ((JSONObject)item).getString("name"));
                return mp;
            }).collect(Collectors.toList());
        }, Collections::emptyList);
    }

    private static List<String> listCommitIds(Object projectId, String since, String until, String refName){
        int pageNo = 1, pageSize = 100;
        List<String> allList = new ArrayList<>();
        boolean hasNext = true;
        while (hasNext){
            System.out.println("listCommitIds: pageNo=" + pageNo+", projectId="+projectId);
            List<String> list = listCommitIds(projectId, since, until, refName, pageNo, pageSize);
            allList.addAll(list);
            pageNo ++;
            hasNext = list.size() >= pageSize;
        }
        return allList;
    }
    
    private static List<String> listCommitIds(Object projectId, String since, String until, String refName, int pageNo, int pageSize){
        String url = "/projects/" + projectId + "/repository/commits?ref_name=" + refName
                + "&page=" + pageNo + "&per_page=" + pageSize
                + "&since=" + since + "T00:00:00+08:00&until=" + until+"T23:59:59+08:00";
        return doGet(url, body -> {
            JSONArray array = JSONArray.parseArray(body);
            return array.stream().map(item -> ((JSONObject)item).getString("id")).collect(Collectors.toList());
        }, Collections::emptyList);
    }

    private static Map<String,Object> getCommitStats(Object projectId, Object commitId){
        String url = "/projects/" + projectId + "/repository/commits/" + commitId;
        return doGet(url, body -> {
            JSONObject data = JSONObject.parseObject(body);
            Map<String,Object> mp = new HashMap<>();
            mp.put("authorName", data.getString("author_name"));
            mp.put("authorEmail", data.getString("author_email"));
            data = data.getJSONObject("stats");
            mp.put("add", data.getInteger("additions"));
            mp.put("delete", data.getInteger("deletions"));
            mp.put("total", data.getInteger("total"));
            return mp;
        }, Collections::emptyMap);
    }


    public static void main(String[] args) {
    	//指定时间段和分支名
        String since = "2024-01-01", until = "2024-01-31", branch = "branch1";

        List<Map<String, Object>> projects = listProjects();

        List<Map<String,Object>> allUserCommits = new ArrayList<>();
        projects.forEach(project -> {
            Object projectId = project.get("id");
            List<String> commitIds = listCommitIds(projectId, since, until, branch);
            commitIds.forEach(commitId -> allUserCommits.add(getCommitStats(projectId, commitId)));
        });

        Map<String, Triple<Integer,Integer,Integer>> userCommitsMap = new HashMap<>();
        allUserCommits.forEach(item -> {
        	if(item==null || item.isEmpty()){
                return;
            }
            String userName = item.get("authorName").toString();
            Triple<Integer,Integer,Integer> triple = userCommitsMap.getOrDefault(userName, Triple.of(0,0,0));
            Integer add = Integer.valueOf(item.get("add").toString());
            Integer delete = Integer.valueOf(item.get("delete").toString());
            Integer total = Integer.valueOf(item.get("total").toString());
            triple = Triple.of(triple.getLeft()+add, triple.getMiddle()+delete, triple.getRight()+total);
            userCommitsMap.put(userName, triple);
        });

        System.out.println("涉及项目("+projects.size()+"):");
        projects.forEach(p -> System.out.println(p.get("name")+" [id="+p.get("id")+"]"));
        System.out.println("----------------------------------------------------------");
        System.out.println("分支:"+branch+", 统计周期: " + since+" ~ " + until);
        System.out.println("----------------------------------------------------------");
        AtomicInteger add = new AtomicInteger(0), delete = new AtomicInteger(0), total = new AtomicInteger(0);
        userCommitsMap.forEach((userName, triple) -> {
            add.getAndAdd(triple.getLeft());
            delete.getAndAdd(triple.getMiddle());
            total.getAndAdd(triple.getRight());
            System.out.println(userName + ": 新增=" + triple.getLeft()+", 删除="+triple.getMiddle()+", 总数="+triple.getRight());
        });
        System.out.println("总计: 新增=" + add.get() + ", 删除=" + delete.get() + ", 总数=" + total.get());
    }
}
5.输出示例:
java 复制代码
涉及项目(3):
saas-project-1 [id=1]
saas-project-2 [id=2]
saas-project-3 [id=3]
----------------------------------------------------------
分支:branch1, 统计周期: 2024-01-01 ~ 2024-01-31
----------------------------------------------------------
张三: 新增=1, 删除=2, 总数=3
李四: 新增=4, 删除=5, 总数=9
王五: 新增=6, 删除=7, 总数=13
总计: 新增=11, 删除=14, 总数=25
相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时4 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang4 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi4 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号4 天前
java函数式编程--入门基础
java·编程·函数式编程