通过TortoiseSVN的客户端Pre-commit hook来进行代码检测

2017-01-25 17:14:54
通过svn客户端的hook来做代码检测
今天发现提交到svn服务器上的php代码多了一行打印信息,是好久以前在本地调试的时候加上的,结果提交svn时忘记删掉了。为了避免此类情况再发生,就想在提交代码时,先做一下检测,小心为上。
svn服务器有hooks的功能,可以做必要的检测,但是会对团队所有成员都起作用,于是就想到在客户端做检测,这样就可以按照自己的需求来定制规则了。
我用的是小乌龟svn客户端, 他也提供了类似于服务器端的hooks功能,正好可以满足我的需求。小乌龟提供了好几种hooks,大体跟svn服务器端保持一致,具体的功能可以直接看网站上的帮助说明,https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html#tsvn-dug-settings-hooks 

这里我要用到的hook是pre_commit hook,就是在你执行提交操作的时候触发,如果发现问题,就直接终止本次commit。我们需要在小乌龟里做一下设置,如下图所示:




Hook Type:我们选择pre_commit Hook
Working Copy Path:就是我们本地的工作目录了
Command Line To Execute: commit时触发的命令,只要windows系统能执行就可以,可以是批处理程序,也可以是其他脚本文件比如php、python等。小乌龟在调用这个命令的时候,会把一些必要的参数传递给命令程序,不同的hook传递的参数不同,比如我们要使用的pre_commit hook会传递comment内容、提交的文件路径等信息。
Wait for the script to finish:注意,这个选项一定要选中,否则commit会直接提交到服务器
Hide the script while running:执行设置的命令时,是否要显示命令窗口,比如DOS窗口,一般我们都会隐藏掉

这样小乌龟的配置就完成了,下面我们就要来完成pre_commit.php文件的编写了,大体思路如下:
1、首先取得这次commit的文件,一个或者多个
2、根据自己的检测规则,挨个分析这些文件

具体代码如下,我这里有两条规则,一条是 commit comment不能为空,一条是代码里不能有 var_dump


<?php
/***
pre_commit 
	argv[0] 程序本身
	argv[1] 本次提交的文件列表,一行一个
	argv[2]  
	argv[3] Log Message File
	argv[4] 工作目录
*/

if(empty($argv[0]) || empty($argv[1]) || empty($argv[2]) || empty($argv[3])) {
	echo 'Something is wrong.';
	exit;
}

$title ="";
$i=0;

//如果没有写log comment,则不允许提交
$log_file = $argv[3];
if(file_exists($log_file)){
	$comment = file_get_contents($log_file);
	$valuableComment = preg_replace('/(^|\s*)(--\S+)(\s*|$)/', '', $comment);

    if (strlen($valuableComment) < 2){
      $title = (++$i).'   comment is empty'.PHP_EOL;
    }
}

//检查提交的文件,是否符合规则
/**
1、对php文件,不能包含var_dump,print_r等调试信息
*/
$commit_file = $argv[1];
if(file_exists($commit_file)){
	$f=fopen($commit_file,'r');
	while($line=fgets($f)){

		if(strpos($line,".php")!==false){

			$file_content = file_get_contents(trim($line));

			if(strpos($file_content,"var_dump")!==false || 
				strpos($file_content,"print_r")!==false
				){
					$title .=(++$i)."   ".trim($line)." is not allowed  including 'var_dump' or 'print_r' string".PHP_EOL;
				}
		}
	}
	
}

if($title){
	$fh = fopen('php://stderr','a'); 
	fwrite($fh,$title);
	fclose($fh);
	exit(1);
}


执行时的结果如下,达到了我们的目的