ตรวจสอบคุณภาพโค้ดก่อน commit ด้วย pre-commit

ในการพัฒนาซอฟต์แวร์ คุณภาพของโค้ดเป็นสิ่งสำคัญอย่างยิ่ง โค้ดที่ดีควรเป็นไปตามมาตรฐานที่กำหนด ผ่านการทดสอบ และปราศจากข้อผิดพลาด หากโค้ดมีคุณภาพดีก็จะทำให้การพัฒนาซอฟต์แวร์เป็นไปอย่างราบรื่น และลดปัญหาที่อาจเกิดขึ้นในอนาคต

หนึ่งในเครื่องมือที่ผมนำมาใช้พัฒนาโค้ดให้มีคุณภาพยิ่งขึ้นคือ pre-commit ซึ่งเป็น Git hook ที่ทำงานก่อนที่จะมีการ commit โค้ด โดย pre-commit สามารถทำงานได้หลากหลายอย่าง เช่น ตรวจสอบความถูกต้องของโค้ดตามมาตรฐานที่กำหนด ทำการทดสอบโค้ด หรือตรวจสอบความเรียบร้อยของไฟล์ต่างๆ

โดยผมอยากจะแนะนำให้นักพัฒนาซอฟแวร์ทุกคนมาใช้ pre-commit กัน

การติดตั้ง pre-commit

สำหรับ osx

$ brew install pre-commit

หรือใช้ pip ติดตั้ง

$ pip install pre-commit

ตรวจสอบ version

$ pre-commit --version
pre-commit 3.3.3

การกำหนด hook ให้กับ pre-commit

เมื่อติดตั้ง pre-commit เรียบร้อยแล้ว เราต้องกำหนด hook ให้กับ pre-commit โดยสร้างไฟล์ .pre-commit-config.yaml ในโฟลเดอร์หลักของโปรเจ็กต์ ไฟล์นี้จะใช้กำหนด hook ต่างๆ ที่เราจะต้องการให้ pre-commit ทำงาน

ไฟล์ .pre-commit-config.yaml จะมีโครงสร้างดังนี้

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: check-added-large-files
        args: ['--maxkb=750']
      - id: check-yaml
        args: ["--allow-multiple-documents"]
      - id: check-json
      - id: detect-private-key
      - id: double-quote-string-fixer
      - id: end-of-file-fixer
      - id: mixed-line-ending
      - id: check-merge-conflict

ในไฟล์นี้เราจะกำหนด hook ต่างๆ ให้กับ pre-commit โดย hook แต่ละตัวจะมี id กำกับอยู่ ซึ่งเราสามารถกำหนด hook ต่างๆ ได้ดังนี้

ID อธิบาย
trailing-whitespace ตรวจสอบว่ามี whitespace ที่ท้ายบรรทัดหรือไม่
check-added-large-files-files ตรวจสอบว่ามีไฟล์ขนาดใหญ่ที่ถูกเพิ่มเข้ามาหรือไม่
check-yaml ตรวจสอบความถูกต้องของไฟล์ YAML
check-json ตรวจสอบความถูกต้องของไฟล์ json
detect-private-key ตรวจสอบว่ามี private key เข้ามาหรือไม่
double-quote-string-fixer แก้ไขให้ใช้ "" กับ String
end-of-file-fixer ตรวจสอบว่ามีไฟล์ที่ไม่มีจุดสิ้นสุดบรรทัดหรือไม่ และแก้ไขให้ถูกต้อง
mixed-line-ending ตาวจสอบถูกต้องของบรรทัดตอนท้ายสุด
check-merge-conflict ตรวจสอบว่ามีไฟล์ที่มีความขัดแย้งระหว่างการ merge หรือไม่

นอกจาก hook เหล่านี้แล้ว เรายังสามารถกำหนด hook อื่นๆ ได้ตามต้องการ โดยสามารถดูตัวอย่าง hook ต่างๆ ได้ที่ https://pre-commit.com/hooks.html

การเพิ่มคำสั่ง Hook เอง

จากตัวอย่างด้านบนเราจะเห็นว่ามันมี Hook ที่เขาทำมาให้เราใช้งานได้เลยทันที แต่ถ้าเราอยากทำ Hook ขึ้นมาเองเช่นให้มัน npm run test ทุกครั้งก่อน Commit สามารถเขียนได้ดังนี้

repos:
  - repo: local
    hooks:
    - id: unitest
      name: Run Unitest
      pass_filenames: false
      language: system
      entry: npm run test
  • id คือ ชื่อ hook
  • nam คือ คำอธิบาย
  • entry คือ คำสั่งที่เราต้องการให้มันทำงาน

การใช้งาน pre-commit

เมื่อกำหนด hook ให้กับ pre-commit เรียบร้อยแล้ว เราจะสามารถใช้งาน pre-commit ได้ โดยทุกครั้งที่เราทำการ commit โค้ด pre-commit จะทำงานตรวจสอบโค้ดตาม hook ที่เรากำหนดไว้ หากโค้ดผ่านการตรวจสอบ pre-commit ก็จะทำการ commit โค้ดให้สำเร็จ แต่ถ้าโค้ดไม่ผ่านการตรวจสอบ pre-commit ก็จะแจ้งให้เราแก้ไขโค้ดก่อนทำการ commit

ทุกครั้งที่มีการ clone project ลงมาที่เครื่องเราใหม่ โดย project นั้นต้องมีไฟล์ .pre-commit-config.yaml อยู่ ให้พิมพ์คำสั่งตามนี้

$ pre-commit install 
$ pre-commit install --hook-type commit-msg 
$ pre-commit autoupdate

ตัวอย่างการใช้งาน pre-commit ดังนี้

$ git commit -m "Add a new feature"

หากโค้ดของเราผ่านการตรวจสอบ pre-commit ก็จะทำการ commit โค้ดให้สำเร็จ แต่ถ้าโค้ดไม่ผ่านการตรวจสอบ pre-commit ก็จะแจ้งให้เราแก้ไขโค้ดก่อนทำการ commit ดังนี้

The following files would be affected by this commit:

  src/main.js

There were some warnings:

  trailing-whitespace: src/main.js:1: trailing whitespace

Please fix the warnings and try again.

และถ้าเราใช้งาน Commit ผ่าน vscode หรือ text editor ที่ใช้งานอยู่ประจำ ก็จะเรียกใช้ pre-commit ด้วยเช่นกัน

ประโยชน์ของการใช้ pre-commit

การใช้ pre-commit มีประโยชน์มากมายดังนี้

  • ช่วยให้เราพัฒนาโค้ดให้มีคุณภาพยิ่งขึ้น โดย pre-commit จะตรวจสอบโค้ดตามมาตรฐานที่กำหนด ทำการทดสอบโค้ด และตรวจสอบความเรียบร้อยของไฟล์ต่างๆ
  • ช่วยให้เราประหยัดเวลาในการแก้ไขโค้ด เนื่องจาก pre-commit จะแจ้งให้เราแก้ไขโค้ดก่อนทำการ commit ทำให้เราสามารถแก้ไขโค้ดได้ทันทีก่อนที่จะทำการ commit
  • ช่วยให้เราลดปัญหาที่อาจเกิดขึ้นในอนาคต เนื่องจาก pre-commit จะตรวจสอบโค้ดให้ถูกต้องตั้งแต่เริ่มต้น
  • สามารถนำไปใช้งานตรวจสอบโค้ดได้ทุกภาษา เช่น python, golang, nodejs เป็นต้น

หากเราพัฒนาซอฟต์แวร์อยู่เป็นประจำ การใช้ pre-commit จะช่วยให้คุณพัฒนาโค้ดให้เป็นไปตามมาตรฐานที่กำหนด ซึ่งจะช่วยให้โค้ดของคุณอ่านง่าย เข้าใจง่าย และนำไปใช้งานต่อได้ง่ายขึ้น นอกจากนี้ การใช้ pre-commit ยังช่วยตรวจสอบความถูกต้องของโค้ดก่อนทำการ commit ทำให้คุณสามารถมั่นใจได้ว่าโค้ดของคุณไม่มีข้อผิดพลาด และพร้อมที่จะนำไปใช้งานจริง

ตัวอย่างไฟล์ pre-commit ที่ใช้ประจำ

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: check-added-large-files
        args: ['--maxkb=750']
      - id: check-yaml
        args: ["--allow-multiple-documents"]
      - id: check-json
      - id: detect-private-key
      - id: double-quote-string-fixer
      - id: end-of-file-fixer
      - id: mixed-line-ending
      - id: check-merge-conflict
  - repo: https://github.com/commitizen-tools/commitizen
    rev: 3.6.0
    hooks:
      - id: commitizen
        stages: [commit-msg]
  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.1-beta
    hooks:
      - id: hadolint-docker
        args: ['--ignore=DL3018']
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.17.0
    hooks:
      - id: gitleaks

นำไปปรับแต่งใช้งานกันนะ...