툴과 개발 환경8 분 읽기

배포 스크립트가 하루치 작업을 되돌릴 뻔했습니다. 돌리기 직전에 봤습니다

고친 문자열을 배포하려고 기존 스크립트를 열어 봤습니다. 그 스크립트는 매 실행마다 리포지토리의 리스팅 파일로 라이브를 덮어씁니다. 전날 API로 고친 47개 필드가 조용히 되돌아갈 뻔했고, 배포는 성공으로 끝났을 겁니다.

#android#tooling#deployment#gotchas#automation
위쪽에 내용이 빽빽한 '라이브' 문서, 아래쪽에 두 줄뿐인 '리포' 문서. 그 사이 굵은 화살표가 아래에서 위로 향하고 화살표에 deploy 라벨이 붙어, 빈약한 리포 내용이 빽빽한 라이브를 덮으려는 모습.
되돌림은 조용합니다. 배포는 성공으로 끝나고, 스토어에는 옛 문구가 올라갑니다.

배포 스크립트를 마지막으로 읽어 본 게 언제입니까? 돌린 게 아니라 읽은 것 말입니다.

저는 그날 읽었습니다. 급하지 않았기 때문입니다. 급했으면 그냥 돌렸을 것이고, 전날 하루치 작업이 조용히 사라졌을 겁니다.

상황

앱 안에 남아 있던 잘못된 문자열을 고쳐서 배포해야 했습니다. 배포 스크립트는 이미 있었습니다. 번들을 올리고, 리스팅을 갱신하고, 커밋하는 것까지 한 번에 합니다.

돌리기 전에 스크립트를 읽었습니다.

스크립트가 라이브를 덮어씁니다

매 실행마다 리포지토리의 리스팅 파일로 라이브를 덮어씁니다.

평소엔 이게 맞습니다. 리포가 정본이고 배포가 그걸 반영하는 구조니까요.

문제는 전날 스토어 리스팅을 API로 대량 수정했다는 것이었습니다. 제목을 현지화하고, 본문을 다시 쓰고, 짧은 설명을 채웠습니다. 그 작업은 스토어에는 반영됐지만 리포지토리 파일에는 반영되지 않았습니다.

대조해 봤습니다.

어긋난 필드
A 47
B 14
C 8
D 0

한 앱은 리포의 영어 본문이 663자, 라이브가 2,000자였습니다. 리포의 제목 16개는 전부 영어, 라이브는 현지화된 것.

그대로 배포했으면 전날 작업이 통째로 되돌아갔을 겁니다. 그리고 그 되돌림은 조용합니다 — 배포는 성공으로 끝나고, 스토어에는 옛 문구가 올라갑니다. 실패 로그도, 경고도 없습니다.

당신이라면 어느 쪽을 정본으로 삼겠습니까

여기서 결정이 하나 필요합니다. 리포가 정본인가, 라이브가 정본인가.

이번엔 라이브가 정본입니다. API로 고친 것이 최신이니까요. 그래서 어긋난 필드를 라이브 값으로 덮어 리포를 맞췄습니다. 반대 방향이 아닙니다.

for 로케일 in 리포_리스팅:
    for 필드 in ("제목", "짧은설명", "전체설명"):
        if 리포[로케일][필드].strip() != 라이브[로케일][필드].strip():
            어긋남.append((로케일, 필드))
            리포[로케일][필드] = 라이브[로케일][필드]

.strip() 이 들어 있는 이유가 있습니다. 일곱 개 로케일에서 모든 줄 앞에 공백 두 칸이 붙어 있던 일이 있어서, 공백만 다른 것을 어긋남으로 세면 목록이 쓸모없어집니다.

같은 스크립트의 다른 결함

인자를 받지 않아서 --dry-run 을 붙여도 무시하고 곧바로 프로덕션에 커밋합니다.

이건 이미 한 번 사고를 낸 적이 있습니다 — 드라이런이 프로덕션에 배포된 일입니다. 지금은 플래그가 오면 죽게 가드가 붙어 있습니다. 무시하는 것보다 죽는 게 낫습니다. 무시하면 사람이 "안전 모드로 돌렸다"고 믿습니다.

리스팅 API 자체도 전체 교체입니다

같이 기억해야 할 게 하나 더 있습니다. 리스팅 갱신 API는 전체 교체입니다.

지정하지 않은 필드는 지워집니다. 한 필드만 고칠 때도 나머지를 읽어서 되채워야 합니다. 이건 앱과 스토어의 언어 목록을 대조할 때도 같은 함정이었습니다.

즉 이 사건은 전체 교체 API + 스테일 리포지토리의 조합입니다. 둘 중 하나만 있으면 안 납니다.

자가진단 3줄

  1. 당신의 배포 스크립트는 어느 방향으로 덮어씁니까? 리포 → 라이브라면, 라이브를 API나 콘솔로 직접 고친 적이 있는지 물어야 합니다.
  2. 배포 전에 대조하는 단계가 있습니까? 없으면 되돌림은 배포 성공과 구분되지 않습니다.
  3. --dry-run 을 모르는 스크립트가 있습니까? 모르면 무시하지 말고 죽어야 합니다.

솔직한 부분

이 위험을 스크립트를 읽어서 발견했지, 자동으로 잡은 게 아닙니다. 급했으면 그냥 돌렸을 것이고, 그랬으면 되돌아간 걸 며칠 뒤에나 알았을 겁니다. 이건 프로세스가 막아 준 게 아니라 그날 제가 시간이 있었던 것뿐입니다.

이번에 한 건 리포 파일을 라이브 값으로 동기화한 것뿐입니다. 구조는 그대로입니다 — 다음에 누가 API로 리스팅을 고치고 리포를 안 맞추면 같은 일이 또 일어납니다. 배포 전에 대조하는 단계를 스크립트에 넣는 게 맞는데, 아직 안 했습니다. 이 글은 그 미완의 기록이기도 합니다.

리포에 라이브에 없는 유령 로케일 폴더도 하나 있었습니다. 왜 있는지 모릅니다. 지우지도 않았습니다 — 모르는 걸 지우는 것도 되돌림입니다.

배포 스크립트가 있으시면, 다음에 돌리기 전에 "이게 무엇을 덮어쓰는가" 한 줄만 확인해 보세요. 되돌림은 실패로 안 보입니다.

관련 글