+2

[Husky Pre-Commit] Husky trong thực chiến: Những điều cần biết (2/4) 🚀

Phần 1: [Husky Pre-Commit] Khám phá cơ bản (1/4) 🚀

Phần 2: [Husky Pre-Commit] Husky trong thực chiến: Những điều cần biết (2/4) 🚀


Xem nhiều hơn tại: https://devvui.one


Vẫn với tinh thần "liều ăn nhiều" 😅

Hi anh em dev 👋, ở bài blog trước, tớ đã chia sẻ về cách cài đặt Husky và lint-staged để tự động hóa việc kiểm tra code trước khi commit. Ban đầu tớ định làm luôn phần check env format với Husky cho nóng... Nhưng có ai ngờ, "đời không như là mơ", vừa triển khai Husky vào dự án thực tế của công ty, tớ đã gặp phải một số vấn đề "dở khóc dở cười" mà chưa từng nghĩ tới 😅

Sau khi tạo PR tích hợp Husky cho tất cả service của công ty, một câu hỏi hiện lên trong đầu:

"Nếu merge cái này vào develop thì có ảnh hưởng gì không nhỉ?"

Lúc đó tớ cũng chưa đoán được hết những ảnh hưởng, nhưng với tinh thần "code một lần, giải quyết vạn vấn đề", tớ quyết định... xúi các bạn trong team merge nhánh của tớ vào nhánh feature của các bạn để thử nghiệm 🤪

Risk It All

Nhưng cái này tớ tự đề xuất làm, chưa kịp báo với anh Leader thì các bạn đã lỡ merge rồi chớ! May mà sau đó thuyết phục được anh leader nên mọi việc cũng ổn 🥲

Bài học rút ra: Mọi thay đổi lớn trong code cần báo với Leader trước kẻo quá muộn! 🤦‍♂️

Vấn đề 1: Merge nhánh feature vào các nhánh test hoặc develop 🔄

Nhánh test thường dùng để tất cả mọi người merge vào để test, nhưng nhánh này rất dễ bị conflict. Khi chạy Husky pre-commit trên những nhánh này, chúng ta đối mặt với hai khả năng:

  1. Husky sửa hàng loạt lỗi linting → Tạo ra nhiều thay đổi không cần thiết
  2. Husky phát hiện lỗi → Chặn commit → Làm gián đoạn quy trình release

Không ổn chút nào! Trong giai đoạn release hay test, chúng ta cần sự ổn định, không phải là thời điểm để format code hay sửa lỗi linting 😫

Giải pháp: Bỏ qua các nhánh quan trọng

#!/bin/bash
BRANCH=$(git rev-parse --abbrev-ref HEAD)

SKIP_BRANCHES=(
  "production/*"
  "test/*"
  "master"
  "develop"
)

for SKIP_BRANCH in "${SKIP_BRANCHES[@]}"; do
  if [[ "$BRANCH" == $SKIP_BRANCH ]]; then
    echo "On protected branch $BRANCH. Skipping lint-staged..."
    exit 0
  fi
done

Vấn đề 2: Merge develop vào branch feature 🌿

Anh em dev thường xuyên merge develop vào branch feature đang phát triển để cập nhật code mới nhất. Tuy nhiên, nhánh develop chứa rất nhiều thay đổi từ các thành viên khác.

Nếu chạy lint-staged khi merge, nó sẽ:

  • Thay đổi nhiều file mà bạn thậm chí không động tới
  • Tạo ra các commit với những thay đổi không liên quan
  • Làm cho PR trở nên khó review vì đầy những thay đổi format, không phải logic

Confused

Giải pháp: Tự động phát hiện và bỏ qua thao tác merge

#!/bin/bash
MERGE_HEAD_FILE=$(git rev-parse --git-dir)/MERGE_HEAD
if [ -f "$MERGE_HEAD_FILE" ]; then
  echo "Merge operation detected. Skipping lint-staged..."
  exit 0
fi

Vấn đề 3: Khi repository có nhiều service bên trong 🏭

Công ty tớ có 7 service trong cùng 1 repository. Hiện tại, mỗi khi chạy lint-staged thì nó sẽ chạy tất cả các lint stage trong từng project, dù bạn chỉ chỉnh sửa code trong một service duy nhất!

Tưởng tượng bạn thay đổi một dòng code trong service A, nhưng phải đợi lint check chạy qua tất cả 7 service... Tốn thời gian vô lý! 🕒

Giải pháp: Chỉ chạy lint-staged cho những service có code thay đổi

#!/bin/bash
ROOT_DIR=$(pwd)
ERROR=0

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)

SERVICES=(
  "portal-web"
  "api-service"
)

has_staged_files() {
  local service_path="applications/$1"
  echo "$STAGED_FILES" | grep -q "^$service_path/"
  return $?
}

for SERVICE in "${SERVICES[@]}"; do
  if has_staged_files "$SERVICE"; then
    echo "Running lint-staged for $SERVICE..."
    (cd "$ROOT_DIR/applications/$SERVICE" && yarn run lint-staged) || ERROR=$?
  fi
done

exit $ERROR

Kết quả mang lại 🎯

Sau khi triển khai script thông minh này, chúng tớ đã thấy những cải thiện rõ rệt:

  1. Tốc độ commit nhanh hơn: Không còn phải đợi lint-staged chạy qua tất cả các service
  2. Tránh được thay đổi không mong muốn: Không còn việc vô tình format code của người khác
  3. Quy trình release an toàn hơn: Husky không còn can thiệp vào các nhánh quan trọng
  4. Trải nghiệm dev thân thiện hơn: Các bạn trong team không còn than phiền về lint-staged nữa 😁

Happy Dev

Những bài học quý giá 🧐

Từ hành trình tích hợp Husky pre-commit vào dự án thực tế, tớ đã học được vài điều:

  1. Không có giải pháp one-size-fits-all: Cấu hình mặc định của Husky không phù hợp với mọi quy trình làm việc
  2. Tôn trọng quy trình hiện tại: Tools phải thích nghi với quy trình của team, không phải ngược lại
  3. Tự động hóa thông minh: Tự động hóa tốt là tự động hóa biết khi nào nên và không nên can thiệp
  4. Tham khảo ý kiến team: Lắng nghe phản hồi từ team để cải thiện công cụ liên tục

Điều gì tiếp theo?

Trong bài tiếp theo của series, tớ sẽ chia sẻ về cách sử dụng Husky để check env format, một vấn đề thường gặp khi làm việc với nhiều service trong cùng một dự án.

Bạn có gặp khó khăn gì khi tích hợp Husky vào dự án thực tế không? Hoặc có giải pháp nào hay ho khác? Hãy chia sẻ trong phần bình luận nhé! 🚀

GitHub Repository: dongitran/husky-pre-commit


Phần 1: [Husky Pre-Commit] Khám phá cơ bản (1/4) 🚀

Phần 2: [Husky Pre-Commit] Husky trong thực chiến: Những điều cần biết (2/4) 🚀


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí