2017-05-09 23 views
6

Tôi có một hậu kiểm và hậu merge githook với những nội dung:Git Hook không âm thầm

#!/bin/bash 
# MIT © Sindre Sorhus - sindresorhus.com 
set -eux 

changed_files="$(git diff-tree -r --name-only --no-commit-id [email protected]{1} HEAD)" 

check_run() { 
    echo "$changed_files" | grep --quiet "$1" && eval "$2" 
} 

echo '' 
echo 'running git submodule update --init --recursive if .gitmodules has changed' 
check_run .gitmodules "git submodule update --init --recursive" 

echo '' 
echo 'running npm install if package.json has changed' 
check_run package.json "npm prune && npm install" 

echo '' 
echo 'running npm build:localhost' 
npm run build:localhost 

Kỳ lạ nếu không có những thay đổi để .gitmodules, kịch bản kết thúc chứ không phải là sự tiến bộ để kiểm tra gói. json. (nó thậm chí không thực thi các dòng echo sau dòng 12)

loại bỏ các lệnh gọi check_run và thay vào đó chỉ cần thực hiện lệnh thẳng thay vì có vẻ hoạt động tốt.

xóa check_run .gitmodules "git submodule update --init --recursive" cũng không hoạt động. Tuy nhiên, hành vi tương tự được trưng bày trong dòng tiếp theo: check_run package.json "npm prune && npm install" nếu package.json chưa được thay đổi

Có điều gì đó mà tôi thiếu mất khiến cho lệnh check_run kết thúc tập lệnh trên thay đổi tệp đầu tiên không được tìm thấy?

trực quan Proof: enter image description here

+0

có thể chỉ định đường dẫn đầy đủ đến nhị phân 'npm'? – t0mm13b

+0

@ t0mm13b nếu bạn nhìn vào hình ảnh bạn có thể thấy rằng nó thậm chí không bao giờ được vào dòng với npm nhưng thay vì thất bại trong/sau grep. Đó là lý do tại sao tôi bao gồm các dòng echo – jth41

+0

ngay cả với grep, bao gồm một đường dẫn đầy đủ đến bất kỳ nhị phân là tốt, tại sao không echo mã lỗi '$?' Của lệnh thực hiện cuối cùng. – t0mm13b

Trả lời

7

Các set -e là vấn đề ở đây: -e có nghĩa là "lối ra nếu có điều gì không", trong đó "thất bại" được định nghĩa là "lối thoát hiểm khác không".

Chúng tôi nhìn thấy trong đầu ra, như một vài dòng cuối cùng:

+ check_run .gitmodules 'git submodule update --init --recursive' 
+ echo '' 
+ grep --quiet .gitmodules 

(và sau đó không có gì khác). Tập lệnh đã thoát sau grep --quiet.

Đây là định nghĩa thực tế của check_run:

check_run() { 
    echo "$changed_files" | grep --quiet "$1" && eval "$2" 
} 

này phân tích như left && right nơi tráiecho ... | grep ...đúngeval "$2".

Chúng tôi thấy rằng phần bên trái chạy và phần bên phải không. Dưới đây là nơi chúng tôi cần biết điều gì đó về shell: ngay cả với -e được đặt, chúng không ngay lập tức thoát nếu có lỗi nào đó, miễn là một cái gì đó là một phần của thử nghiệm. Vì vậy, đây không phải là vấn đề ngay lập tức.

Nhưng nó vẫn là vấn đề, bởi vì left && right có, như trạng thái thoát, trạng thái thoát của điều cuối cùng nó chạy. Điều cuối cùng nó chạy là đường ống bên trái, là echo ... | grep .... Trạng thái thoát của đường ống là trạng thái thoát của thành phần cuối cùng của nó, tức là, grep. Các grep thoát số không nếu nó tìm thấy chuỗi (và với --quiet, cũng ngăn chặn đầu ra của nó), 1 nếu không, và 2 trên các lỗi chung, do đó trạng thái thoát là 1.

Do đó, trạng thái thoát của left && right là cũng 1.

Do đó, kể từ khi -e có hiệu lực, trình bao đã thoát!

Việc chữa bệnh là để tránh -e (nhưng điều này có nghĩa là nếu có lỗi khác không mong muốn, vỏ cày, vì vậy điều này có thể hơi nguy hiểm) hoặc để đảm bảo rằng left && right không làm cho thoát khỏi trình bao.

Có một cách đơn giản để làm sau này: thay thế left && right với if left; then right; fi:

if echo "$changed_files" | grep --quiet "$1"; then 
    eval "$2" 
fi 

Lưu ý rằng nếu eval "$2" thất bại, vỏ sẽ vẫn thoát.

Có cách khác và hơi phức tạp để thực hiện việc này với hiệu ứng khác: thay thế left && right bằng left && right || true. Các "và" biểu hiện liên kết chặt chẽ hơn, vì vậy điều này có nghĩa:

  • Đánh giá trái
  • Nếu mà thành công (thoát zero), đánh giá đúng
  • Nếu && thất bại (hoặc trái thoát nonzero hoặc phải được chạy và phải thoát khỏi không đồng bộ), đánh giá phần || true, thoát khỏi 0.

Do đó:

echo "$changed_files" | grep --quiet "$1" && eval "$2" || true 

luôn thoát 0, eval -ing "$2" khi và chỉ khi ở phía bên trái bị lỗi (không tìm thấy grepped-cho expression).

Nếu bạn muốn check_run để cày ngay cả khi eval "$2" không thành công, hãy sử dụng phiên bản thứ hai (|| true). Nếu bạn muốn check_run để dừng (và có toàn bộ lối thoát) dưới -e nếu eval "$2" không thành công, hãy sử dụng phiên bản đầu tiên (if ...; then).


Thực sự cổ 4BSD /bin/sh, rất lâu trước khi nó đã đi mã nguồn mở, có một lỗi: -esẽ làm cho lối ra vỏ trong những trường hợp này. (Tôi nghĩ rằng tôi đã cố định bản thân mình vào một thời điểm, nhưng khi 4BSD chuyển sang một sh ​​mới, không dựa trên mã gốc của Steve Bourne, thì lỗi đó không có ở đó chút nào.)

Trong bash, bạn có thể kiểm soát điều này chi tiết hơn. Cụ thể, bạn có thể nhận được trạng thái mỗi thành phần của một đường ống trong biến mảng $PIPESTATUS.

+0

Cảm ơn một nhóm! – jth41

Các vấn đề liên quan