<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>scm | 伪架构师</title>
    <link>/tags/scm/</link>
      <atom:link href="/tags/scm/index.xml" rel="self" type="application/rss+xml" />
    <description>scm</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Wed, 05 Aug 2015 10:32:19 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>scm</title>
      <link>/tags/scm/</link>
    </image>
    
    <item>
      <title>在版本管理过程中增强Drupal编码标准控制</title>
      <link>/post/drupal-coding-standard-control-in-scm/</link>
      <pubDate>Wed, 05 Aug 2015 10:32:19 +0800</pubDate>
      <guid>/post/drupal-coding-standard-control-in-scm/</guid>
      <description>&lt;p&gt;根据&lt;a href=&#34;https://drupal.org&#34; target=&#34;_blank&#34;&gt;Drupal.org&lt;/a&gt;的统计结果，Drupal社区共拥有：&lt;/p&gt;

&lt;p&gt;＊ 27098个模块&lt;/p&gt;

&lt;p&gt;＊ 2012个主题&lt;/p&gt;

&lt;p&gt;＊ 827个发行版&lt;/p&gt;

&lt;p&gt;＊ 33875个开发者&lt;/p&gt;

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

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

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

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

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

&lt;p&gt;如何保证呢？简单的办法就是，不合规则的代码不许提交。&lt;/p&gt;

&lt;p&gt;使用&lt;a href=&#34;https://www.drupal.org/project/coder&#34; target=&#34;_blank&#34;&gt;Coder&lt;/a&gt;，&lt;a href=&#34;https://www.drupal.org/project/coder&#34; target=&#34;_blank&#34;&gt;Coder Review&lt;/a&gt;，&lt;a href=&#34;https://github.com/drush-ops/drush&#34; target=&#34;_blank&#34;&gt;Drush&lt;/a&gt;，pre-commit/pre-push钩子等很多方法都能够保证提交到版本库的代码是符合规范的。本文将聚焦于Drush和Git的集成，而不会详细讲解Drupal管理界面的Coder模块。&lt;/p&gt;

&lt;p&gt;#Coder, Coder Review以及Coder Sniffer模块&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.drupal.org/project/coder&#34; target=&#34;_blank&#34;&gt;Coder模块&lt;/a&gt;是一个插件管理器。Coder模块自带的Coder Review和Coder Sniffer是两个标准包，包含了实际的标准测试。下面是我们将要提及的一些相关内容：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drupal CodeSniffer&lt;/li&gt;
&lt;li&gt;Drupal Sequrity Checks&lt;/li&gt;
&lt;li&gt;Drupal SQL Standards&lt;/li&gt;
&lt;li&gt;Drupal Commenting Standards&lt;/li&gt;
&lt;li&gt;Internationalization&lt;/li&gt;
&lt;li&gt;Drupal Coding Standards&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;#Coder Reivew和Drush的集成&lt;/p&gt;

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

&lt;pre&gt;&lt;code&gt;  drush @local.drupal coder janrain –minor –ignore –no-empty –reviews=sniffer,security,sql,comment,i18n,style –ignorename –ignores-pass
&lt;/code&gt;&lt;/pre&gt;

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

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

&lt;p&gt;#Git集成&lt;/p&gt;

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

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

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

&lt;p&gt;下面是两个代码文件：&lt;code&gt;pre-commit&lt;/code&gt;以及&lt;code&gt;pre-commit_janrain&lt;/code&gt;。这些代码由带有&lt;code&gt;-git&lt;/code&gt;选项的Review命令生成，其中有一些适应环境的本地修改。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pre-commit&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/php
&amp;lt;?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 = &amp;quot;/Users/lpeabody/Sites/drupal/sites/all/modules/janrain/.git&amp;quot;;

/**
* Return array of pre-commit_ files with their full relative paths.
*/
function find_pre_commit($dir = &#39;.&#39;) {
 $files = array();
 foreach (scandir($dir) as $file) {
   if (substr($file, 0, 11) == &#39;pre-commit_&#39; &amp;amp;&amp;amp; is_executable(&amp;quot;$dir/$file&amp;quot;)) {
     $files[] = &amp;quot;$dir/$file&amp;quot;;
   }
   elseif ($file != &#39;.&#39; &amp;amp;&amp;amp; $file != &#39;..&#39; &amp;amp;&amp;amp; is_dir(&amp;quot;$dir/$file&amp;quot;)) {
     $files = array_merge($files, find_pre_commit(&amp;quot;$dir/$file&amp;quot;));
   }
 }
 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);
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;pre-commit_janrain&lt;/strong&gt;&lt;/p&gt;

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

$PATH = getenv(&#39;PATH&#39;);
// need to add drush to the system path
putenv(&amp;quot;PATH=/usr/local/bin:$PATH&amp;quot;);

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

// 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(&#39;git rev-parse --verify HEAD 2&amp;gt; /dev/null 2&amp;gt;&amp;amp;1&#39;, $dummy, $ret);
$against = ($ret == 0) ? &#39;HEAD&#39; : &#39;4b825dc642cb6eb9a060e54bf8d69288fbee4904&#39;;
exec(&amp;quot;git diff --cached --name-only $against&amp;quot;, $files);

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

// Run coder against the .git files.
$cmd = &amp;quot;drush $CODER_ARGS&amp;quot;;
print &amp;quot;Coder pre-commit: $cmd\n - &amp;quot; . implode(&amp;quot;\n - &amp;quot;, $files) .&amp;quot;\n\n&amp;quot;;
system($cmd . &#39; &#39; . implode(&#39; &#39;, $files), $ret);
if ($ret) {
 exit($ret);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;#串起来&lt;/p&gt;

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

&lt;pre&gt;&lt;code class=&#34;language-pre-commit```只是一个通用的方法，用于载入我们自行创建的```pre-commit```钩子。载入过程依赖于命名规则，要将自定义的pre-commit钩子按照```pre-commit_hookname```方式进行命名。&#34;&gt;
&lt;/code&gt;&lt;/pre&gt;

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

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