在版本管理过程中增强Drupal编码标准控制

根据Drupal.org的统计结果,Drupal社区共拥有:

* 27098个模块

* 2012个主题

* 827个发行版

* 33875个开发者

另外,来自230个国家,说着181种不同语言的107万4000多个用户在使用Drupal。上述数据完全来自Drupal社区。

我想要花时间来说一下这一条:27098个模块,这些模块由大约33875个开发者贡献的巨量代码构成。世上没有两片相同的树叶,如此众多的开发者,当然也可能产生各自的编码风格,如果这样下去,一个模块的代码对于其他开发者来说,可能就完全是晦涩难懂的了。

编码规范很重要,尤其是对于Drupal这种大规模项目来说。规范的代码能让初次接触项目的开发者不至于一头雾水。在规范代码的帮助下,新晋者可以顺利的进入代码并顺利完成工作,而无需在奇怪的变量命名和古怪的代码格式上浪费时间。

Drupal实现了大量的规范。从简单的代码格式,到复杂的安全实现,都被这些规范所涵盖。每个Drupal模块都要遵守这些标准。如果所有的模块都满足这一要求,那么Drupal就能够在安全、性能以及易读性方面更上一层楼。

我们用来进行代码编写的IDE和一些编辑器能够根据这些标准规则,进行实时的代码检查,所以我们推荐开发过程使用这些工具,不过工具问题不是本文的重点。你当然可以用自己的方式来保存代码,提交代码到你在使用的版本库中;但如果要向Drupal提交,那么就要保证这些代码是符合规范的。

如何保证呢?简单的办法就是,不合规则的代码不许提交。

使用CoderCoder ReviewDrush,pre-commit/pre-push钩子等很多方法都能够保证提交到版本库的代码是符合规范的。本文将聚焦于Drush和Git的集成,而不会详细讲解Drupal管理界面的Coder模块。

#Coder, Coder Review以及Coder Sniffer模块

Coder模块是一个插件管理器。Coder模块自带的Coder Review和Coder Sniffer是两个标准包,包含了实际的标准测试。下面是我们将要提及的一些相关内容:

  • Drupal CodeSniffer
  • Drupal Sequrity Checks
  • Drupal SQL Standards
  • Drupal Commenting Standards
  • Internationalization
  • Drupal Coding Standards

这里不准备对上述功能进行深入讲解,这些字面功能都很直观。可能以后对这些功能以及相关标准进行逐个的详细介绍。

#Coder Reivew和Drush的集成

这里假设读者对Drush有一定使用经验, 所以我不会讲解Drush本神的内容。这里我要多说一句就是:Drush是Drupal管理方面的最佳工具。借助Drush可以做很多有趣的事情,例如在命令行上进行Code Review。下面举个例子:

  drush @local.drupal coder janrain –minor –ignore –no-empty –reviews=sniffer,security,sql,comment,i18n,style –ignorename –ignores-pass

上面的命令告诉Drush调用Coder模块,对Janrain模块进行reviews参数中指定的Review,并声明启用忽略功能,不显示成功通过的信息(-no-empty),显示被忽略的规则名称(-ignorename),以及测试所有级别的规则(-minor)。-ignore-pass选项告诉Coder不要对被忽略的警告进行计数,这一设置对pre-commit以及pre-push hooks很有用。除非显式的声明这一参数,否则产生的警告信息可能被当做命令的错误码返回。针对这种情况,我提出了一个补丁,https://www.drupal.org/node/1974654

同样的,所有在末尾列出的文件也都在被Review的范围中。可以使用drush help coder命令来获取完整的命令和参数列表。

#Git集成

上面的内容中,我们已经可以在命令行上进行Code Review了。Coder还有进一步的考虑就是,Review结果会用退出码的方式返回。退出码一般是Review过程中产生的警告和错误的总和。这里顺便做一下科普,当执行一个Shell命令时,如果其退出码不等于零,则代表该命令执行失败。所以,Review过程中产生任何的警告和错误,都代表着命令执行失败。

返回码问题在进行pre-commit或pre-push的集成中尤为重要。大致说来,如果Review失败,就不可能进行代码提交,所以应该只有把代码修改到100%符合Review标准之后才能提交成功。

接下来我们使用一个pre-commit钩子。这里要求每次提交的代码必须满足指定的Review标准,所以这是一个相当严格的规定,所以如果提交的频率很高,可能需要一个pre-push之类的本地方法,会让这个过程没那么烦躁。

下面是两个代码文件:pre-commit以及pre-commit_janrain。这些代码由带有-git选项的Review命令生成,其中有一些适应环境的本地修改。

pre-commit

#!/usr/bin/php
<?php
/**
* @file
* Generic .git pre-commit hook runs all pre-commit hooks
* following the naming convention of pre-commit_example.
*
* This script was created by drush coder-review --git.
* Do not modify.
*/
$GITPATH = "/Users/lpeabody/Sites/drupal/sites/all/modules/janrain/.git";

/**
* Return array of pre-commit_ files with their full relative paths.
*/
function find_pre_commit($dir = '.') {
 $files = array();
 foreach (scandir($dir) as $file) {
   if (substr($file, 0, 11) == 'pre-commit_' && is_executable("$dir/$file")) {
     $files[] = "$dir/$file";
   }
   elseif ($file != '.' && $file != '..' && is_dir("$dir/$file")) {
     $files = array_merge($files, find_pre_commit("$dir/$file"));
   }
 }
 return $files;
}

// Run each pre-commit script.
foreach (find_pre_commit($GITPATH) as $pre_commit) {
 system($pre_commit, $ret);
 if ($ret != 0) {
   // Exit as soon as one of the scripts returns an error.
   exit($ret);
 }
}

pre-commit_janrain

#!/usr/bin/php
<?php
/**
* @file
* Coder pre-commit hook.
*
* This script was created by drush coder-review --git.
* Do not modify.
*/

$PATH = getenv('PATH');
// need to add drush to the system path
putenv("PATH=/usr/local/bin:$PATH");

$GITPATH = '/Users/lpeabody/Sites/drupal/sites/all/modules/janrain/.git';
$GITRELATIVE = 'sites/all/modules/janrain';
$CODER_ARGS = '@local.drupal coder janrain --minor --ignore --no-empty --reviews=sniffer,security,sql,comment,i18n,style --ignorename --ignores-pass';

// Find the files that are ready to checkin.
// The magic revision is for an initial commit: diff against an empty tree object.
// See .git/pre-commit.sample.
exec('git rev-parse --verify HEAD 2> /dev/null 2>&1', $dummy, $ret);
$against = ($ret == 0) ? 'HEAD' : '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
exec("git diff --cached --name-only $against", $files);

// Convert .git relative path to DRUPAL_ROOT relative.
foreach ($files as &$file) {
 $file = "$GITRELATIVE/$file";
}

// Run coder against the .git files.
$cmd = "drush $CODER_ARGS";
print "Coder pre-commit: $cmd\n - " . implode("\n - ", $files) ."\n\n";
system($cmd . ' ' . implode(' ', $files), $ret);
if ($ret) {
 exit($ret);
}

#串起来

把上面两个文件放到本地Git仓库的hooks目录中,版本化过程现在就有了增强的编码标准检查了。可以根据不同需求对这两个文件进行修改,例如调整各文件的顶层变量等。你可能也想要调整其中的Drush命令,例如不同的站点别名等。


pre-commit_janrain```是真正执行任务的位置。简单说来,这个钩子会在每次本地提交的时候对janrain模块进行review。每个接触过的文件,只要不是在忽略范围之内,都需要100%的复合Drupal规范,才能够进行提交。如果在这个模块中发现了任何不合规则的情况,提交都会失败。

这真的很简单,就是这一简单规则让Drupal社区称为一个整体。如果我们所有的代码都复合标准,Drupal就会是一个更健壮、更具效率也更安全的平台。Drupal在这一基础上会持续成长,不断强化代码。这也是每个Drupaller乐见其成的。

Avatar
崔秀龙

简单,是大师的责任;我们凡夫俗子,能做到清楚就很不容易了。

comments powered by Disqus
下一页
上一页

相关