Tuts: Sử dụng git precommit hooks và php_cs để tự động review code trước khi commit

Spread the love

Vấn đề : sau khi code và test nhiều khi ta có thể quên các đoạn debugger, có thể ta vi phạm một số coding convention (không được sử dụng trong dự án)

Hôm nay mình chia sẻ kinh nghiệm để có thể áp dụng git pre commit hooks và php code sniffer để auto review code theo một tiêu chuẩn nhất định do mình định nghĩa

1. Các định nghĩa

1.1 Git Hooks là gì

Tạm định nghĩa sơ lược thì git hooks là các đoạn scripts sẽ được thực thi khi một lệnh git được gọi ở terminal tương ứng. Các git repository đều có thư mục .git/hooks để chứa các đoạn script. Các event của git ta có thể áp dụng hook được liệt kê như trong url bên phải http://githooks.com/

Nội dung thư mục .git/hooks
1.2 PHP Code Sniffer là gì

Là một open source cho phép ta  tokenize PHP , JS hoặc CSS để phát hiện các vi phạm liên quan đến tiêu chuẩn coding .PHP CodeSniffer cũng có hỗ trợ sẵn các bộ tiêu chuẩn như PEAR, PSR1, PSR2 , Zend … hoặc ta có thể tự define bộ tiêu chuẩn theo mỗi dự án riêng rẽ

2. Cách cài đặt PHP Code sniffer

Trên github của php code sniffer cũng có chỉ các cách để install php_cs bao gồm

2.1 Install thông qua curl

Cách đơn giản nhất nhẹ nhàng nhất

curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar

Cách trên sẽ down về 1 file php có tên là phpcs.phar. Ta có thể chạy từ thẳng từ terminal mà không cần phải config (tất nhiên là chỉ tại ngay thư mục đó thôi , còn gọi từ nơi khác qua thì phải có full đường dẫn)

2.2 Install bằng PEAR
Nếu đã cài PEAR, chúng ta có thể cài thông qua PEAR. Cái này nhanh ở chỗ khỏi config gì cả và ta có thể chạy ở bất kì đâu

`pear install PHP_CodeSniffer`

2.3 Install bằng COMPOSER
2.4 Chạy thử php cs

Mở terminal tại thư mục dự án, ta gọi lệnh như bên dưới

phpcs app/Http/Controllers

thì kết quả sẽ như hình

Các đoạn code vi phạm cùng với lỗi sẽ được output ra như bên trên.

Lưu ý để biết phpcs được chạy ở thư mục nào ta dùng lệnh

which phpcs

/c/Users/GodStorm/AppData/Roaming/Composer/vendor/bin/phpcs

Default thì phpcs sẽ dựa vào file config phpcs.xml.dist để check file standard cơ sở ( default sẽ là PHPCS) tuy nhiên ta cũng có thể cho chạy theo standard khác. Như bên dưới khi thực thi

phpcs --standard=MyStandard app/Http/Controllers/

thì kết quả output sẽ khác

Tiếp theo ta sẽ next sang phần tự define standard của mình

3. Tự define standards cho PHPCS

Để tự define standard cho PHPCS ta cần làm các bước bên dưới

3.1 Tìm file bin của phpcs

Di chuyển đến thư mục có chứa file bin của phpcs (ở trên ta có thể dùng lệnh which phpcs để tìm ra thư mục tương ứng)

(theo như hình bên dưới thì nó đang ở trong composer)

3.2 Tạo cấu trúc thư mục Standard :

Cấu trúc standard của Sniffs bao gồm

MyStandard : thư mục chính

MyStandard/Sniffs : thư mục chứa các implementation về coding standards

MyStandard/ruleset.xml: file xml chứa thông tin cũng như định danh về thư mục chứa các tiêu chuẩn để sniff

3.3 Tạo file Sniff

Một file sniff là 1 file PHP mà phải được đặt vào bên trong thư mục ta đã tạo ở mục 3.2, ngoài ra nó còn phải được kết thúc bởi Sniff.php
Trong thư mục Sniffs, chia thành nhiều thư mục con , với mỗi thư mục hướng đến một đối tượng ví dụ như

  • Arrays : Các tiêu chuẩn khi coding mảng
  • Classes: Liên quan đến các tiêu chuẩn khi coding classes
  • CodeAnalysis : Liên quan đến cấu trúc
  • Commenting : Liên quan đến comment code
  • ControlStructures : Liên quan đến khối lệnh hệ thống (do while, loop, if else)
  • Files : Tiêu chuẩn khi coding file
  • Formatting: tiêu chuẩn khi format code
  • Functions: Tiêu chuẩn khi code hàm
  • Metrics : Các metrics khi code (vd: không được quá 500 LOC cho 1 hàm , không được if x lần lồng nhau)
  • NamingConventions : Các quy tắc khi đặt tên biến, constant, hà, class….

Ngoài ra có thể dùng kết hợp với các online tools review khác như jshint.com, csslint.com …. Có thể tìm hiểu kĩ hơn trong php_codesniffer\CodeSniffer\Standards\Generic\Sniffs\Debug

Chúng ta sẽ cùng tạo thử một hàm để check có weak comparison (so sánh sử dụng ==) trong code hay không nhé

3.3.1 Chúng ta sẽ tạo DisallowWeakComparisonSniff.php

Bất cứ file sniff nào cũng phải implements interface PHP_CodeSniffer_Sniff. Trong interface đó có 2 hàm quan trọng là

  • register : đăng kí các token mà PHP Code sniffer sẽ sniff, một khi mà phpcs tìm đc token đã đăng kí thì hàm process sẽ được gọi
  • process: hàm này sẽ được gọi từ bên register, với tham số là file được sniff và và vị trí mà token được tìm thấy trong file đó

Ví dụ đoạn code của chúng ta như bên dưới

public function register()
 {
   return array(T_IS_EQUAL);
 }//end register()
 /**
 * Processes the tokens that this sniff is interested in.
 *
 * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found.
 * @param int $stackPtr The position in the stack where
 * the token was found.
 *
 * @return void
 */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     if ($tokens[$stackPtr]['content']{0}) {
       $error = 'We dont allow weak comparison , found %s';
       $data = array(trim($tokens[$stackPtr]['content']));
       $phpcsFile->addError($error, $stackPtr, 'Found', $data);
     }
 }//end process()

Đoạn code trên

  • register : sẽ bắt các chỗ có dùng token T_IS_EQUAL
  • process: hàm này sẽ được gọi từ bên register, với tham số là file được sniff và và vị trí mà token được tìm thấy trong file đó, nếu có, thì sẽ add lỗi WeakComparison vào biến `$phpcsFile`

Chạy đoạn code trên ta có

Vậy là đã tạm xong bước phpcs. Bây giờ ta sẽ chuyển qua bước sử dụng git hooks

4. Tạo file git-precommit hooks để gọi php_cs mỗi khi chúng ta thực hiện git-commit

Mình down file , git-precommit hooks đã được tạo sẵn trên git hub ở đây

Trong link trên có 2 file

  • pre-commit : là file hooks đã được mod lại để gọi phpcs trước khi thực hiện git commit thật sự (có nghĩa là nếu phpcs trả về bất kì lỗi gì thì lệnh git commit sẽ không được thực hiện :D)
  • config : file config trong đó có thể settings các biến kiểu như
    • PHPCS_BIN: thư mục để file binary của phpcs
    • PHPCS_CODING_STANDARD: coding standard mà bạn muốn dùng
    • PHPCS_IGNORE: list các file patterns bỏ qua
    • PHPCS_FILE_PATTERN: list các file pattern sẽ sniff
    • PHPCS_IGNORE_WARNINGS: bật tắt ignore cảnh báo
    • PHPCS_ENCODING: encoding

File git hooks pre-commit mình cũng không có sửa gì nhiều. Chủ yếu là chỉ sửa lại phần output (để có thể liệt kê ra nhiều thông tin hơn thôi )

OUTPUT=$($PHPCS_BIN $STAGED_FILES $IGNORE_WARNINGS --standard=$PHPCS_CODING_STANDARD)

Chỉ sửa mỗi đoạn trên để loại bỏ bớt vào params dư thừa mà mình cho là ít dùng (đối với mình)

Và bên dưới là kết quả

 

Vậy là sau này chúng ta có thể tự động review code với mỗi lần gọi git commit rồi 🙂

Chúng ta có thể tự xây dựng một bộ code review thật hiệu quả cho từng dự án như vậy sẽ giảm thiểu được rủi ro khi coding cũng như các bạn mới sẽ dễ dàng tiếp cận hơn được với dự án

Trong quá trình viết bài này mình có tìm thấy vài trang web sau để đánh giá code cũng khá hiệu quả

  • jshint.com : trang này để đánh giá code js, theo khá nhiều tiêu chí như compatible với ES bao nhiêu, những đoạn code nào dễ phát sinh lỗi, tính toán thống kê (độ dài code, phức tạp )
  • csslint.com : trang này dùng để đánh giá css (mình ít dùng css nên cũng ko rành, có lẽ các bạn designer sẽ cần nhiều hơn)

Hi vọng chúng ta có thể tạo ra những đoạn code : đẹp – hiệu quả – dễ maintain.