有效代码行数预研方案

作者: 才兄说 | 来源:发表于2018-10-08 23:54 被阅读32次

    欢迎到个人博客阅读

    前言

    公司这边其实已经使用sonar对代码进行了统计,但需求想要更加明确的统计每个user单独的代码量,以便对该user的工作质量进行评估。sonar目前只有对整个目录文件的代码行数统计,对于git merge之类的代码没有区别得很细,也就是说不断merge别人的代码也会被统计到当前提交的user上,而我们是需要明确每个user具体提交了多少代码量,然后下面是针对有效代码行数预研的方案及试错,有需要的朋友可以参阅,少走弯路。

    已实现:
    提交通过的代码可以用sonar统计行数。Num2-Num1=有效行数(实际开发行数)
    存在问题:
    如果过程中分支有从别的分支合并代码过来,会造成统计时混合了其他分支代码。

    处理方案

    方案一:(客户端方案)

    1.情况一,当前功能分支一直提交,并没有merge其他分支来支持当前分支开发,那么可以通过每次提交成功后统计该分支的有效行数,通过之前已实现的sonar方案。
    2.情况二,f2分支在开发过程中,如需要引用f1分支的功能作为开发支撑,这种情况需要在客户端的git仓库中埋点,使用git hook(post-merge)监听,当pull f1并merge成功后,触发post-merge监听,接着执行通知,告知接收者几个关键参数(合并的分支、合并成功后总代码行数),接收者收到入参后,接着统计合并分支的代码行数,然后 合并后的总行数-当前统计分支行数=合并进来的行数,以后每次f1分支提交统计代码行数时,都减去“合并进来的行数”得到提交的有效行数。

    方案二:(服务端方案)

    拉取分支后,云效在未合并完成前,不允许拉取合并其他分支。监听用户的在服务端的post-receive触发,如果与第一次拉取做一个对应关系。

    方案三:(本地客户端hook,优化版本)

    本地客户端方案关键点:
    hook脚本注入,本地代码统计方案,merge、commit触发执行脚本,shell脚本post交互
    (实现全局hook,本质也是本地配置引用,需要配置干预。与直接copy都是需要人为本地干预 no)
    1.hook脚本注入:hook文件自动copy暂时没有触发入口(方案:云效流程干预)
    2.shell脚本post交互:云效上有sonar数据的拦截处理层,这部分之前是我们自己处理,api交互补充逻辑即可。
    方案步骤:
    1.拉取分支,然后给一个勾选的触发,弹窗,选择远程的hook和本地仓库目录(目录/.git/hooks)
    在云效这里,由于客户端pull动作无法知道完成时机,要么云效定时循环检测目录存在,然后注入远程hook,要么培训说明人为判断拉取成功后必须手动勾选,然后注入远程hook,两个方式目的都是想办法把远程的hooks文件注入到本地的hooks目录中。
    2.本地代码统计(难点,在不安转三方支持的情况下,怎么统计分支除merge之外的纯代码量,暂时只统计新增行)
    那么考虑能否从文件本身的角度入手,监听或合适时机主动获取文件数量和文件总行数。把过程中产生纯新增行数记录到并合适时机告诉接收者。
    3.shell通过curl发送post请求:
    curl -d parm1=111&param2=222 http://www.baidu.com
    4.本地每次merge与本地commit只有hook存在,都能触发对应的脚本程序。

    实验情况:
    1.测试本地存在hook脚本的情况,在本地分支merge和commit两个关键动作都能触发执行脚本。

    image
    本地提交,成功触发pre-commit脚本:
    image
    本地分支merge,成功触发post-merge脚本:
    image

    2.测试目录文件数及总行数:
    获取本地仓库目录下,所有文件书和行数:shell脚本测试ok


    image

    补充:
    1)能否去除空行,注释行。(使用grep排除空行和注释行,sed和tee用法)
    2)缓存对比数据方案(本地?远程?)
    3)test.sh在统计文件数和行数,不包括.git目录的。


    image
    执行结果:
    image
    3.测试修改文件了,先merge再commit,确定行数获取时机。

    答:merge之前,git的操作是必须需要先本地commit当前分支,否则合并失
    败。(保证当前分支是最新的节点)
    这里就解决了,统计merge之前和merge之后的代码行数。统一由commit时产
    生的行数作为计算基准数。
    当前分支未commit就执行merge动作:


    image
    当前分支已commit,执行merge动作,触发脚本计算行数:
    image

    方案四:服务器端,分析.git,分离每个user提交的代码信息,分别获取对应的行数。(选用方案)

    脚本代码:统计总行数、历史删除、增加的总行数

    git log --author="hans" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "增加的行数:%s 删除的行数:%s 总行数: %s\n",add,subs,loc }' 
    

    注意:该方法统计,最后一行如果是空行,不纳入行数计算,如果不是则纳入。
    测试场景:
    用户hans:
    1.master分支有10行,在master上创建分支t1,t1分支新增5行。分别获取master行数、t1行数
    master行数10:

    image
    t1行数15:
    image

    2.上传t1分支,让用户tt克隆项目,tt用户在master的基础上新建分支t2,新增行数8,提交。分别获取hans提交行数,tt提交行数。


    image

    把t2合并进入master,再次统计master上不同用户提交的代码行数,hans行数10,tt行数8,符合预期有效行数。


    image
    补充:hans电脑上传master(已合并t2),下图是tt电脑上,拉取最新的master,然后再次分别获取对应行数。
    对于tt用户来说,虽然master上行数变为18行,但统计tt的提交量还是8行,符合预期有效行数。

    [图片上传失败...(image-dc6ef-1539014498277)]
    3.测试同一个文件下,不同用户操作,并统计行数。
    在hans电脑上,如果发生冲突的部分,会导致tt用户提交的这部分冲突代码统计失败,还是原来的8行,只有hans的代码新增了,由原来的10行,新增了5行。


    image
    在tt用户电脑,master上pull回来,统计同hans电脑结果。
    [图片上传失败...(image-d1a9f6-1539014498277)]

    结论:
    1.为了统计用户有效代码行数,建议每个用户在commit的行都是新的行,如果在别的用户行上修改,统计时是不纳入你的代码行数。
    2.每个分支上,用户之间提交的代码行数都是相互隔离的,可以分别获取对应用户提交的代码行数,与merge无关。
    3.在实际应用上,虽然shell脚本已经编写完毕,但是由于系统间在执行过程中会存在权限问题,不保证每个系统都稳定能执行到脚本。最终讨论的方案是,通过Java调用git命令来执行git的信息统计,后面会针对该内容专门开一篇文章分享。

    相关资料

    git hooks钩子:

    那么钩子什么时候被执行,Git预定义了触发时机:
    ClientSide hooks:
    1 pre-commit,当执行commit动作时先执行此hook,可以用此hook做一些检查,比如代码风格检查,或者先跑测试。
    2 prepare-commit-msg, 当commit时需要输入message前会触发此hook,可以用此hook来定制自己的default message信息。
    3 commit-msg,当用户输入commit的message后被触发,可以用此hook校验message的信息,比如是否符合规定,有没有cr等。
    4 post-commit, 当commit完成后被触发,可以用此hook发送notification等。
    5 pre-rebase, rebase之前会被触发,可以用此hook来拒绝所有的已经push的commits进行rebase操作。
    6 post-merge, 当merge成功后,会触发此hook。
    7 pre-push, 当push时,remote refs被更新,但是在所有的objects传输前被触发。
    8 pre-auto-gc, 当git gc --auto执行前被触发。在垃圾回收之前做一些验证或备份是挺不错的。

    ServerSide hooks:
    1 pre-receive, 当收到push动作之前会被执行。
    2 update, 也是收到push动作之前被执行,但是有可能被执行多次,每个branch一次。
    3 post-receive, 当push动作已经完成的时候会被触发,可以用此hook来push notification等,比如发邮件,通知持续构建服务器等。

    git log相关信息:

    统计某人的代码提交量,包括增加,删除:
    git log --author="(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add +=1 ; subs += 2 ; loc +=1 - 2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' - 仓库提交者排名前 5(如果看全部,去掉 head 管道即可): git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5 仓库提交者(邮箱)排名前 5:这个统计可能不会太准,因为很多人有不同的邮箱,但会使用相同的名字 git log --pretty=format:%ae | gawk -- '{ ++c[0]; } END { for(cc in c) printf "%5d %s\n",c[cc],cc; }' | sort -u -n -r | head -n 5
    贡献者统计:
    git log --pretty='%aN' | sort -u | wc -l
    提交数统计:
    git log --oneline | wc -l
    添加或修改的代码行数:
    git log --stat|perl -ne 'END { print c }c += $1 if /(\d+) insertions/;

    git log 参数说明:
    --author 指定作者
    --stat 显示每次更新的文件修改统计信息,会列出具体文件列表
    --shortstat 统计每个commit 的文件修改行数,包括增加,删除,但不列出文件列表:
    --numstat 统计每个commit 的文件修改行数,包括增加,删除,并列出文件列表:
    -p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新
    例如:git log -p -2
    --name-only 仅在提交信息后显示已修改的文件清单
    --name-status 显示新增、修改、删除的文件清单
    --abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
    --relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)
    --graph 显示 ASCII 图形表示的分支合并历史
    --pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)
    例如: git log --pretty=oneline ; git log --pretty=short ; git log --pretty=full ; git log --pretty=fuller
    --pretty=tformat: 可以定制要显示的记录格式,这样的输出便于后期编程提取分析
    例如:git log --pretty=format:""%h - %an, %ar : %s""
    下面列出了常用的格式占位符写法及其代表的意义。
    选项 说明
    %H 提交对象(commit)的完整哈希字串
    %h 提交对象的简短哈希字串
    %T 树对象(tree)的完整哈希字串
    %t 树对象的简短哈希字串
    %P 父对象(parent)的完整哈希字串
    %p 父对象的简短哈希字串
    %an 作者(author)的名字
    %ae 作者的电子邮件地址
    %ad 作者修订日期(可以用 -date= 选项定制格式)
    %ar 作者修订日期,按多久以前的方式显示
    %cn 提交者(committer)的名字
    %ce 提交者的电子邮件地址
    %cd 提交日期
    %cr 提交日期,按多久以前的方式显示
    %s 提交说明
    --since 限制显示输出的范围,
    例如: git log --since=2.weeks 显示最近两周的提交
    选项 说明
    -(n) 仅显示最近的 n 条提交
    --since, --after 仅显示指定时间之后的提交。
    --until, --before 仅显示指定时间之前的提交。
    --author 仅显示指定作者相关的提交。
    --committer 仅显示指定提交者相关的提交。

    一些例子: 
    // 一分钟之前的所有 
    git log --until=1.minute.ago 
    
    //一天之内的log 
    log git log --since=1.day.ago 
    
    //一个小时之内的log 
    git log --since=1.hour.ago 
    
    //一个月之前到半个月之前的log 
    git log --since=`.month.ago --until=2.weeks.ago 
    
    //某个时间段的log 
    git log --since ==2013-08.01 --until=2013-09-07 
    
    //看看某一个文件的相关历史记录
    git blame
    例如:git blame index.html --date short

    相关文章

      网友评论

        本文标题:有效代码行数预研方案

        本文链接:https://www.haomeiwen.com/subject/ncmsaftx.html