Skip to content
isdnetworks
Go back

훅 입력에 없던 작업

(수정됨)

GitLab 서버의 post-receive 훅 스크립트를 검토했다. 커밋에 적힌 Jira 작업 키를 추출해 이슈에 댓글을 달라는 지시가 있었다. 그 지시는 커밋 메시지가 훅 입력으로 들어온다는 전제 위에 서 있었다.

Table of contents

Open Table of contents

검증 — 입력을 찍어 본 이유

스크립트는 입력의 구조를 가정하고 짜여 있고 그 가정이 맞는지는 코드만 읽어서는 알 수 없다. 그래서 cat > /tmp/hook-stdin.txt 한 줄을 넣었다. 실제로 들어오는 표준 입력을 파일로 떨어뜨려 봤다.

떨어진 파일을 열어 보니 들어 있는 것은 oldrev newrev refname 한 줄, 즉 식별자와 참조 이름뿐이었다. git 공식 문서의 githooks 대로 post-receive 는 갱신된 참조마다 그 한 줄을 받을 뿐이다. 지시가 전제한 커밋 메시지는 아예 들어 있지 않았다.

원인 — 전제한 정보가 없었다

그러면 커밋에서 작업 키를 추출하라는 그 지시는 실행될 수가 없는 것이다. 그런데 스크립트는 오류를 내지 않고 빈 문자열로 Jira API 를 부르고 끝난다.

전제가 틀리면 그 전제 위의 지시가 통째로 무효가 되는데 실행은 성공으로 끝난다. 두 가지 방법이 있었다. 하나는 훅 안에서 git log oldrev..newrev --format=%s 로 메시지를 직접 꺼내는 것이다. 다른 하나는 훅은 refname 만 넘기고 추출은 Jenkins 잡이 하게 하는 것이다. 앞쪽을 골랐다. 이유는 어차피 훅이 저장소 안에서 도는 자리라 git log 가 가장 가까워서다. 대신 훅이 커밋 수만큼 느려지는 것을 감수했다.

이벤트마다 다른 출력 처리

두 번째로 확인한 것은 post-receive 가 스크립트의 종료 코드를 아예 보지 않는다는 점이었다. 같은 문서대로 pre-receive 는 종료 코드로 푸시를 거부한다. post-receive 는 실제 작업이 끝난 뒤에 불리므로 결과에 영향을 주지 않는다.

일반적인 설명이 모든 훅에 그대로 적용되는 것처럼 읽히는 것이 이 오해의 원인이었다. exit 1 을 아무리 돌려줘도 그 훅에서는 제어에 쓰이지 않는다.

셸 치환이 깨지는 자리

세 번째는 따옴표를 이스케이프하려고 쓴 ${msg//\"/\\\"} 셸 문자열 치환이었다. $ 나 & 같은 다른 특수문자가 섞이면 변수 확장이나 매치 참조로 해석돼 예상 밖의 결과가 나온다.

가공 순서도 나빠서 이스케이프 함수에 도달하기 전에 셸 치환 단계에서 이미 값이 깨졌다. 문자열을 셸 치환으로 가공하지 않고 jq -R 에 맡기는 방식으로 바꿨다.

조용한 오류의 자리

이 셋의 공통점은 전부 오류를 내지 않고 잘못 동작한다는 점이었다. 빈 검색어로 API 를 부르고 종료 코드가 무시되고 값이 깨진 채로 진행되는데 실행 자체는 성공한다.

본체 로직은 결과가 화면에 나오므로 틀리면 드러난다. 훅은 배경에서 돌아 안 도는 것과 잘못 도는 것을 구분하기 어렵다. 그래서 훅은 표준 입력과 출력과 종료 코드를 직접 봐야 했다.

정리


Share this post on:

Previous Post
절반을 제외하던 도구
Next Post
있었는데 안 찾아본 것