一、背景:
? ? ? ?需要對(duì)當(dāng)前公司所有的項(xiàng)目進(jìn)行代碼行數(shù)的統(tǒng)計(jì)
二、 可實(shí)現(xiàn)方式
? ? ? ?1.腳本:通過(guò)git腳本將所有的項(xiàng)目拉下來(lái)并然后通過(guò)進(jìn)行代碼行數(shù)的統(tǒng)計(jì)
? ? ? ? 樣例:
echo 創(chuàng)建項(xiàng)目對(duì)應(yīng)的文件夾 mkdir 項(xiàng)目名稱echo 切到創(chuàng)建的文件夾中 cd 項(xiàng)目名稱echo 進(jìn)行g(shù)it初始化 git init echo 添加遠(yuǎn)程倉(cāng)庫(kù) git remote add origin 項(xiàng)目地址 git fetch origin git checkout -b master origin/master echo 切換檢出的分支為master git branch echo 拉取項(xiàng)目代碼 git pull origin master echo 將項(xiàng)目名稱追加輸出到上級(jí)目錄的projectCount.txt文件中注意逗號(hào)分隔 echo 項(xiàng)目名稱, >> ../projectCount.txt echo 使用git命令統(tǒng)計(jì)該項(xiàng)目的代碼行數(shù)并將結(jié)果追加到上級(jí)目錄的projectCount.txt文件中 git ls-files | xargs cat | wc -l >> ../projectCount.txt cd .. echo 創(chuàng)建項(xiàng)目對(duì)應(yīng)的文件夾 mkdir 項(xiàng)目名稱 ... 將該代碼保存成sh腳本,在gitbash命令行執(zhí)行
將所有的項(xiàng)目進(jìn)行腳本處理之后便可以得到一張項(xiàng)目名稱,代碼行數(shù)的txt文件,因?yàn)橐远禾?hào)分隔故轉(zhuǎn)換成csv文件后可以復(fù)制到excel中進(jìn)行統(tǒng)計(jì)排序處理
? ? ? ?2.gitlab提供的有標(biāo)準(zhǔn)的API接口可以通過(guò)調(diào)用API的方式進(jìn)行統(tǒng)計(jì)
? ? ? ? ?在網(wǎng)上進(jìn)行一番的搜索發(fā)現(xiàn)已經(jīng)有封裝好的SDK包添加maven依賴后可以直接使用
? ? ? ? ?樣例:
? ? ? ? 引入maven依賴,如果需要其他的版本可以到github上面找到對(duì)應(yīng)的版本:https://github.com/gitlab4j/gitlab4j-api
<!-- gitlab-api SDK--> <dependency> <groupId>org.gitlab4j</groupId> <artifactId>gitlab4j-api</artifactId> <version>5.3.0</version> </dependency>
? ? ? ?統(tǒng)計(jì)所有項(xiàng)目的代碼行數(shù):
? ? ?
private String url = "gitlab的倉(cāng)庫(kù)地址"; private String authToken = "用戶的token"; private GitLabApi gitLabAPI = new GitLabApi(url, authToken); /** * 統(tǒng)計(jì)每個(gè)項(xiàng)目的代碼行數(shù) * * @throws Exception */ @Test public void codeTotalCount() throws Exception { //拉取屬于我的所有項(xiàng)目 List<Project> projectList = gitLabAPI.getProjectApi().getOwnedProjects(); for (Project proj : projectList) { String namespace = proj.getNamespace().getFullPath(); String name = proj.getPath(); String url = proj.getWebUrl(); log.info("項(xiàng)目命名空間:{}, 項(xiàng)目名稱:{}, 項(xiàng)目地址:{}", namespace, name, url); //獲取項(xiàng)目信息包含statistics信息 Project project = gitLabAPI.getProjectApi().getProject(namespace, name, true); ProjectStatistics projectStatistics = project.getStatistics(); Long totalLines = projectStatistics.getRepositorySize(); log.info("項(xiàng)目名稱:{}, 代碼行數(shù):{}", name, totalLines); } }
? ? ? 統(tǒng)計(jì)某一段時(shí)間人員的代碼行數(shù):
? ? ? ??
private String url = "gitlab倉(cāng)庫(kù)地址"; private String authToken = "用戶的token"; private GitLabApi gitLabAPI = new GitLabApi(url, authToken); /** * 統(tǒng)計(jì)人員某段時(shí)間的代碼行數(shù) * * @throws Exception */ @Test public void codeAuthorCount() throws Exception { gitLabAPI.enableRequestResponseLogging(Level.ALL); List<Project> projectList = gitLabAPI.getProjectApi().getOwnedProjects(); //獲取項(xiàng)目中的人員信息 List<User> userList = getMembers("in"); log.info("查詢?nèi)藛T列表:{}", JSON.toJSONString(userList)); Date start = DateUtil.parse("2023-07-01 00:00:00", "yyyy-MM-dd HH:mm:ss"); Date end = DateUtil.parse("2023-10-01 00:00:00", "yyyy-MM-dd HH:mm:ss"); for (User user : userList) { Integer addCode = 0; Integer delCode = 0; Integer totalCode = 0; String name = user.getName(); String userName = user.getUsername(); String state = user.getState(); //檢查用戶信息,不符合要求的用戶如 blocked 可進(jìn)行跳過(guò) if (checkUserInfo(name, state)) { continue; } for (Project p : projectList) { List<Commit> commitList = gitLabAPI.getCommitsApi().getCommits(p.getId(), "master", start, end); for (Commit commit : commitList) { //因commit信息中沒(méi)有用戶的memberId信息,每個(gè)人提交信息有些缺失故進(jìn)行多次判斷 if (userName.contains(commit.getAuthorName()) || commit.getCommitterEmail().contains(userName) || commit.getAuthorEmail().contains(userName)) { Commit c = gitLabAPI.getCommitsApi().getCommit(p.getId(), commit.getShortId()); //添加代碼行數(shù) addCode += c.getStats().getAdditions(); //刪除代碼行數(shù) delCode += c.getStats().getDeletions(); //累計(jì)修改行數(shù) totalCode += c.getStats().getTotal(); } } } log.info("開(kāi)始時(shí)間:{},結(jié)束時(shí)間:{},姓名:{}, 添加代碼行數(shù):{}, 刪除代碼行數(shù):{}, 累計(jì)變更行數(shù):{}", start, end, name, addCode, delCode, totalCode); } } private boolean checkUserInfo(String name, String state) { if (state.equals("blocked") || name.contains("產(chǎn)品部") ) { return true; } return false; } /** * 獲取項(xiàng)目與group中的人員信息 * * @param groupPath * @return * @throws Exception */ private List<User> getMembers(String groupPath) throws Exception { List<User> userList = new ArrayList<>(); //獲取所有組路徑下的人員信息 List<Group> groupList = gitLabAPI.getGroupApi().getGroups(); List<Project> projectList = new ArrayList<>(); for (Group g : groupList) { log.info("組名稱:{}, 組路徑:{}", g.getDescription(), g.getFullPath()); List<Member> members = gitLabAPI.getGroupApi().getMembers(g.getId()); projectList.addAll(gitLabAPI.getGroupApi().getProjects(g.getId())); for (Member m : members) { if (!checkMemberExist(userList, m)) { User user = gitLabAPI.getUserApi().getUser(m.getId()); userList.add(user); } } } //獲取所有Project的人員信息 for (Project project : projectList) { String name = project.getPath(); Long id = project.getId(); log.info("項(xiàng)目名稱:{}, 項(xiàng)目Id:{}", name, id); List<Member> members = gitLabAPI.getProjectApi().getMembers(id); for (Member m : members) { if (!checkMemberExist(userList, m)) { User user = gitLabAPI.getUserApi().getUser(m.getId()); userList.add(user); } } } return userList; } /** * 判斷人員是否已經(jīng)存在 * * @param userList * @param m * @return */ private boolean checkMemberExist(List<User> userList, Member m) { for (User user : userList) { if (user.getId().equals(m.getId())) { return true; } } return false; }