Skip to content

release: preview 브랜치 push 실패가 성공으로 보고되던 문제 수정 - #175

Merged
dldnsgkr merged 2 commits into
mainfrom
develop
Aug 27, 2026
Merged

release: preview 브랜치 push 실패가 성공으로 보고되던 문제 수정#175
dldnsgkr merged 2 commits into
mainfrom
develop

Conversation

@dldnsgkr

Copy link
Copy Markdown
Collaborator

develop → main. #174 하나뿐이고 마이그레이션 변경은 없다.

무엇을 고치나

git push 가 종료 코드를 읽지 않는 exec 로 돌아서, 실패해도 호출자가 성공으로 알았다.

그 결과 사용자에게 이렇게 안내된다.

작업물을 preview 브랜치에 올렸습니다. 프리뷰가 만료돼도 코드는 남습니다.

push 가 실패했다면 거짓이다. 컨테이너가 만료되는 순간 작업물이 사라지고, 감사 로그에는 PREVIEW_BRANCH_PUSHED 가 성공으로 남아 추적도 안 된다. 안전하다고 들은 것을 잃는다.

해결

실패가 의미 있는 단계만 execWithExitCode 로 바꾸고 비-0 이면 던진다(git init, remote add/set-url, checkout -B, add, commit, push). apk addgit config 는 그대로 둔다 — 이미 git 이 있거나 이미지가 alpine 이 아닐 수 있어 그것까지 실패로 보면 멀쩡한 컨테이너에서 푸시가 막힌다.

예외 메시지에는 명령 전문을 넣지 않는다. 이 클래스는 자격 증명을 다루고 메시지는 로그와 화면으로 흘러간다.

호출부는 이미 이 예외를 전제로 쓰여 있었다

  • ResultApprovalGate javadoc: 예외가 AgentPlanExecutor catch-all 로 전파돼 태스크 FAILED(재시도 가능)
  • RepositoryBindingService: "push 가 실패하면 트랜잭션이 통째로 롤백되므로" 를 근거로 연결 저장을 push 앞에 둔다
  • 저장소 생성은 repositoryExists 로 멱등이라 재시도가 같은 저장소를 재사용한다

설계는 그렇게 돼 있었고 예외만 오지 않았다. CLAUDE.md 의 "push 실패 시 스텝이 완료로 넘어가지 않는다"도 이제 참이 된다.

검증

  • 마이그레이션 없음
  • 테스트 6개 추가(실패가 성공으로 보고되지 않는지 / 메시지에 토큰이 없는지 / 앞 단계가 깨지면 push 전에 멈추는지 / 빈 커밋은 실패가 아닌지 등), 기존 DeployAgentServiceTest 갱신
  • ./gradlew test 전체 통과, CI 통과, dev 배포 성공(2dc6c9f) 및 기동 확인(200)

🤖 Generated with Claude Code

dldnsgkr and others added 2 commits August 27, 2026 10:12
git push 가 exec 로 돌고 있었는데 그 메서드는 종료 코드를 읽지 않는다. 인증 실패든
보호 브랜치든 그냥 문자열이 돌아왔고, 호출자는 성공으로 알고 다음으로 갔다.

그 대가가 크다. 감사 로그에는 PREVIEW_BRANCH_PUSHED 가 성공으로 남고, 사용자에게는
"작업물을 preview 브랜치에 올렸습니다 — 프리뷰가 만료돼도 코드는 남습니다"가
표시된다. 실제로는 아무것도 올라가지 않았고, 컨테이너가 만료되면 작업물은 사라진다.
사용자는 안전하다고 들은 것을 잃는다.

CLAUDE.md 에 적힌 "push 실패 시 스텝이 완료로 넘어가지 않는다"는 보장도 실제로는
성립하지 않았다. 그 문장은 push 실패가 예외로 올라올 때만 참이다.

실패가 의미 있는 단계만 execWithExitCode 로 바꾸고 비-0 이면 던진다 — git init,
remote add/set-url, checkout -B, add, commit, push. apk add 와 git config 는 그대로
둔다. 이미 git 이 깔려 있거나 이미지가 alpine 이 아닐 수 있어서, 그것까지 실패로
보면 멀쩡히 돌던 컨테이너에서 푸시가 막힌다 — 정말 git 이 없으면 뒤의 strict 단계가
드러낸다.

commit 은 변경이 없으면 git diff --cached --quiet 가 0 으로 끝나 건너뛴다. 변경이
있으면 1 을 주고 커밋이 돌며 그 커밋이 실패해야 비-0 이 된다. 그래서 strict 로 둬도
"고칠 것이 없었다"가 오류가 되지 않는다.

예외 메시지에는 명령 전문을 넣지 않는다. 이 클래스는 자격 증명을 다루고, 메시지는
로그와 사용자 화면으로 흘러간다 — 단계 이름과 git 출력만 남긴다.

호출부는 이미 이 예외를 전제로 쓰여 있었다. ResultApprovalGate 는 javadoc 에
AgentPlanExecutor 의 catch-all 로 전파돼 태스크가 FAILED 가 된다고 적어뒀고,
RepositoryBindingService 는 "push 가 실패하면 트랜잭션이 통째로 롤백된다"를 근거로
연결 저장을 push 앞에 둔다. 저장소 생성도 repositoryExists 로 멱등이라 재시도가
같은 저장소를 재사용한다. 설계는 이미 그렇게 돼 있었고 예외만 오지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(agent): preview 브랜치 push 실패가 성공으로 보고되던 문제
@dldnsgkr
dldnsgkr merged commit 2df6275 into main Aug 27, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant