빌드는 실패했는데 커밋 도우미는 통과시켰습니다
빌드 로그를 grep으로 거른 뒤 마지막 명령의 종료값을 읽어 실패한 빌드를 통과시켰습니다. 변경을 되돌려 고치고, zsh의 pipestatus로 빌드 결과를 확인하는 방법을 정리했습니다.
들어가며
2026년 10월 15일, Phone Cleaner를 여러 단계로 나눠 리팩토링하고 있었습니다. 각 단계가 끝나면 검사와 빌드를 돌리고 커밋하는 도우미를 썼습니다. 일곱 번째 단계에서 빌드가 깨졌는데도 커밋이 만들어졌습니다.
grep의 성공을 빌드 성공으로 읽었습니다
도우미는 빌드를 실행한 뒤, 긴 출력을 줄이려고 뒤에 붙인 grep의 종료값을 보고 있었습니다.
별도 파이프 실패 처리가 없는 셸에서는 a | b 전체의 종료값이 마지막 명령 b의 결과를 따릅니다. 빌드가 실패해도 grep이 찾는 줄을 발견하면 grep은 성공할 수 있습니다. 오류 문장을 잘 찾아낸 결과가 빌드 성공처럼 전달된 셈입니다.
Gradle의 종료값을 직접 확인하기
깨진 변경은 되돌린 뒤 다시 고쳤습니다. 도우미가 확인해야 할 값도 일지에 남겼습니다. zsh에서는 공식 문서의 pipestatus에 마지막 파이프라인의 각 명령 종료값이 들어 있습니다.
아래는 그 검사 방식을 줄여 적은 zsh 예시입니다. 당시 명령을 그대로 복사한 것은 아닙니다.
./gradlew assembleDebug 2>&1 | tee build.log | grep -E 'BUILD|error:'
build_status=${pipestatus[1]}
if (( build_status != 0 )); then
exit "$build_status"
fi
첫 번째 명령인 Gradle의 종료값을 파이프라인 직후 저장합니다. 다른 명령을 실행한 뒤에는 pipestatus가 바뀔 수 있으므로 먼저 보관해야 합니다. tee는 전체 로그를 남기고 grep은 화면에 보여줄 줄을 고를 뿐입니다.
마치며
그날의 기록에는 여러 변경이 한 커밋에 섞인 문제도 남아 있습니다. 다음 도우미에는 커밋할 파일을 한 단계의 변경으로 좁히고, 빌드 명령이 0을 반환했을 때만 커밋하도록 조건을 두기로 했습니다. 검사는 이미 돌고 있었는데 그 실패를 넘기는 곳에서 놓쳤습니다.