在TortoiseSVN提交前自动检查代码

背景 | Context

SVN是软件项目中广泛使用的版本控制工具,其作用涉及到软件过程中的多个环节。TortoiseSVN可以集成于Windows系统资源管理器中,简便易用,被很多Windows环境开发人员选作SVN客户端。除了常用的Checkout, Update, Commit等功能,TortoiseSVN还有一些高级特性可以为开发者提供更多便利,比如我现在介绍的“Client Side Hook Scripts | 客户端‘钩子’脚本”。

关于钩子 | Hooks

Hook机制被广泛使用于系统开发和应用程序框架,是为软件提供可扩展性的一种手段。Hook机制的一种基本实现是:在主程序/框架代码控制流上的某些节点调用一个约定的函数,扩展代码则通过重写这个约定的函数来实现在特定时机的扩展功能。(参见WordPress PlugIn API)。在不同的系统中Hook也有很多其它形式的表现。一般来说hook不被设计为影响主要流程的因素。

TortoiseSVN客户端的钩子们 | TortoiseSVN Client Side Hooks

作为一种需要编译后运行的软件,TortoiseSVN以调用用户配置的外置脚本(比如批处理文件,com+,以及本文例子中的WScript)的形式实现hook(而非在代码中加入扩展函数)。TortoiseSVN为SVN中使用频度最高的两个操作commit和update提供了六个“钩子”如下:

  • start-commit: 在用户选择commit功能,而commit对话框出现之前被调用。
  • pre-commit: 在用户在commit对话框上选定将要提交的文件并写好日志,点击提交,而客户端向SVN服务器发送数据之前。
  • post-commit: 无论提交是否成功,在提交过程完成后,post-commit hook将被调用。
  • start-update: 在update-to-revision对话框出现之前被调用。
  • pre-update: 在用户确认更新,而实际向服务器取回数据的动作发生之前被调用。
  • post-update: 无论更新是否成功,在更新完成之后被调用。

在调用任何一个钩子脚本的时候,TortoiseSVN会将此时可用到的信息作为参数传入脚本中。比如当前工作路径,影响到的文件,版本,可能的错误信息等等。关于TortoiseSVN Client Side Hooks的更多信息请参阅TortoiseSVN文档中的相关章节

故事 | Story

麻烦 | Troubles

以下两端废话的大意是我们有时会不小心向SVN提交一些不该提交的代码,所以需要一些除了态度以外更好的办法来对将要提交的代码进行必要的检查:
我所在前端开发团队几乎每天都要使用Firebug──一种用于前端调试的很棒的Firefox扩展。为了在javascript运行时设置断点,我们会在代码中加入”debugger;”语句,同时”console.log”常常被用于在代码的某处向Firebug控制台输出某个对象,以便我们查看运行时数据。问题是,这些语句只有当Firebug存在(以及IE8在打开开发者工具)的时候才会被正常执行,否则执行至此处时javascript引擎将抛出异常,中断其后的过程。
在开发过程前期,将含有调试代码的改动提交到SVN不会有明显的危害,开发者也可以在某个关键版本前将所有此类代码移除。但是随着项目推进,QA, Writer, Build等不同团队介入,越来越多的“用户”会在不定时使用SVN上的代码。想像一下,项目经理使用最新的Build去给老板演示,却发现所有的主要功能都莫名其妙的无法完成,是怎样的一种窘境。
显然,将用于调试的代码提交至SVN多多少少是一种不职业。但是就我所在的团队的现实而言,我们在前后一年的时间里没有解决这个问题。态度决定一切这种话应该理解为“没有态度万万不行”,而只有态度没有好的方法恐怕也难以解决问题。所以我们需要一种方法,帮助粗心的开发者避免这种麻烦。

方法 | Manner

TortoiseSVN的客户端钩子脚本刚好提供了这样一种方便,这种方式显然应该更早被想到而不是问题发生一年之后。办法很简单,只要在用户选定将要提交的文件,而提交发生之前的pre-commit hook上设置一个脚本,用以检查将要提交的代码,如果发现任何被禁止提交的字符串则向TortoiseSVN返回一个错误消息即可。TortoiseSVN提供了设置Hooks的图形界面,而WScript可以使用javascript作为脚本让另一部分也变得很简单。

步骤 | Steps

1. 脚本 | Scripts

TortoiseSVN将四个参数传入pre-commit hook,依次是:PATH | 以“每行一个”的形式存储“此次操作涉及的文件的路径”的临时文件的路径,DEPTH | 深度(参考SVN的depth概念),MESSAGEFILE | 存储提交日志的临时文件,CWD | 当前工作路径。
我们可以从PATH指向的文件中获取所有涉及的文件,逐一读取并检查它们的内容,如果任何文件含有“违禁”的内容,则返回一个错误码,中断SVN的提交过程。以下是javascript的参考代码:

/**
 * Script for checking code before commit to svn repo
 * Hook type: pre commit
 * Author: xiaohwan at gmail.com
 * Date: Mar 22
 * 
 * Update "targets" to add or remove forbidden words.
 */
var targets = ["console.log", "debugger"];
var objArgs, num;
// NOTE: verify arguments. <a href="http://msdn.microsoft.com/en-us/library/at5ydy31%28VS.85%29.aspx">WScript reference</a>;
objArgs = WScript.Arguments;
num = objArgs.length;
if (num != 4) {
    WScript.Echo("Usage: [CScript | WScript] PreCommit.js path/to/pathsfile depth path/to/messagefile path/to/CWD ");
    WScript.Quit(1);
}
// NOTE: read contents of committing files &amp; check if there's any "forbidden" word.
var paths = readPaths(objArgs(0));
while (paths.length) {
  var path = paths.shift();
  var contents = readFile(path);
  for (var i = 0; i  -1) {
      WScript.stderr.writeLine("Do you really want to check-in code with \"" + targets[i] + "\"?");
      WScript.stderr.writeLine("Please check \"" + path + "\" or turn off pre-commit-hook in svn setting then try again.");
      // NOTE: failed, quit with error code;
      WScript.Quit(1);
    }
  }
}
// NOTE: passed verification, continue to commit;
WScript.Quit(0);
function readFile(path) {
  var contents = readPaths(path);
  return contents.join("\n");
}
function readPaths(path) {
	var retPaths = new Array();
	var fs = new ActiveXObject("Scripting.FileSystemObject");
	if (fs.FileExists(path))
	{
		var a = fs.OpenTextFile(path, 1, false);
		var i = 0;
		while (!a.AtEndOfStream)
		{
			var line = a.ReadLine();
			retPaths[i] = line;
			i = i + 1;
		}
		a.Close();
	}
	return retPaths;	
}
2. 设置 | Setup
配置钩子脚本

打开TortoiseSVN设置,选择Hook Scripts,点击右下角“Add...”,在弹出对话框的右上角选择Pre-Commit Hook,选择Working Copy Path和脚本文件的路径。不要忘记在脚本文件路径之前加上“WScript”。勾选下面的两个选项。

3. 效果 |

设置完成以后,所有用户将要提交的代码都将收到脚本的检查,确认没有任何不适于提交的内容。在此例中,尝试提交含有禁止字符串“debugger”的代码将引起以下的信息:

错误信息

尝试提交含有禁止字符串“debugger”的代码将引起图中的信息

更多 | More

本文所涉及的实例中只用到了pre-commit hook,在我看来这个钩子也是六个中可能最有用的一个。其次可能是post-update,以便用户根据update的结果做出处理。当然不同的项目,不同的开发者都会有各自的需求。不管怎样,TortoiseSVN Client Hooks是可以为开发过程提供方便的不错的工具。

This entry was written by Wang Xiaoxing , posted on Tuesday March 23 2010at 09:03 am , filed under Javascript, SVN and tagged , , , , , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>