bluetape4k-dependencies 제작기 Part 3: Maven Central에는 롤백 버튼이 없다

Part 2에서는 1.0.0 BOM을 공개 계약으로 만들 때
정한 경계를 살펴봤습니다. 중앙 BOM은 각 저장소 BOM을 가져오고, 사용자는 중앙 BOM 하나를 적용하며, 버전
카탈로그는 유지보수자의 빌드 작성 계약으로 남깁니다.
여기까지는 구조 이야기입니다. 구조를 만들고 나면 그다음부터는 배포가 기다립니다.
특히 Maven Central에 한 번 게시한 릴리스 아티팩트는 같은 버전으로 교체할 수 없습니다.
1.3.0까지 운영하며 확인한 핵심 원칙은 다음과 같습니다.
릴리스 트레인에서 게시 후 수정은 같은 버전을 교체하는 작업이 아니라 새 패치 버전을 게시하는 작업이다.
스냅샷 버전 행렬과 릴리스 버전 행렬은 다르다
섹션 제목: “스냅샷 버전 행렬과 릴리스 버전 행렬은 다르다”개발 중에는 스냅샷 버전이 필요합니다. 여러 저장소가 동시에 변경되므로 develop에서는 다음 릴리스 트레인의
스냅샷 버전을 미리 연결해 검증합니다.
예를 들어 1.3.0을 준비하던 시점의 개발 참조 버전은 다음과 같았습니다.
bluetape4k-bom:1.11.0-SNAPSHOTbluetape4k-aws-bom:0.4.0-SNAPSHOTbluetape4k-exposed-bom:1.11.0-SNAPSHOTbluetape4k-graph-bom:0.6.0-SNAPSHOTbluetape4k-image-bom:0.3.0-SNAPSHOTbluetape4k-javers-bom:0.3.0-SNAPSHOTbluetape4k-leader-bom:0.4.0-SNAPSHOTbluetape4k-text-bom:0.3.0-SNAPSHOT그러나 이 목록을 그대로 릴리스 버전 행렬로 사용하면 안 됩니다. 실제 1.3.0 안정 버전 후보는 다릅니다.
| 상위 BOM | 1.2.0 입력 | 1.3.0 안정 버전 후보 |
|---|---|---|
bluetape4k-bom | 1.10.0 | 1.11.0 |
bluetape4k-aws-bom | 0.3.1 | 0.4.0 |
bluetape4k-exposed-bom | 1.10.0 | 1.11.0 |
bluetape4k-image-bom | 0.2.0 | 0.3.0 |
bluetape4k-text-bom | 0.2.0 | 0.2.1 |
bluetape4k-graph-bom | 0.5.0 | 0.5.1 |
bluetape4k-leader-bom | 0.3.1 | 0.4.0 |
bluetape4k-javers-bom | 0.2.0 | 0.2.1 |
graph는 다음 개발선에서 0.6.0-SNAPSHOT을 사용하더라도 이번 안정 릴리스에는 0.5.1을 넣어야 했습니다.
javers도 마찬가지입니다. 다음 개발 버전과 현재 릴리스 입력을 섞으면 중앙 BOM이 실제로 게시되지 않은 조합을
공개하게 됩니다.
이런 실수는 코드 리뷰에서 놓치기 쉽습니다. 버전 숫자가 비슷하고, 스냅샷은 “어차피 다음 버전”이라는 착각을 만들기 때문입니다. 그래서 문서에 버전 행렬을 고정했습니다. 사람의 기억에 의존하는 검증 절차는 릴리스 통과 조건이 될 수 없습니다.
Maven Central에서 조회되기 전에는 릴리스 입력이 아니다
섹션 제목: “Maven Central에서 조회되기 전에는 릴리스 입력이 아니다”공개 릴리스 BOM은 스냅샷 아티팩트를 참조하면 안 됩니다. 여기에 더해 해당 릴리스 아티팩트가 Maven Central에서 실제로 조회되는지도 확인해야 합니다.
잘못된 순서: 1. dependencies BOM에서 aws 0.4.0을 가리킨다. 2. dependencies BOM을 먼저 배포한다. 3. aws 0.4.0은 아직 Central에 없다. 4. 사용자는 BOM import 단계에서 깨진다.
맞는 순서: 1. aws 0.4.0을 배포한다. 2. Central에서 aws 0.4.0 BOM이 조회되는지 확인한다. 3. dependencies BOM이 aws 0.4.0을 가리키게 한다. 4. dependencies BOM을 마지막에 배포한다.코드 변경만 보면 작은 차이지만 사용자에게 미치는 영향은 작지 않습니다. 사용자는 내부 릴리스 트레인의 게시 순서를 알 수 없습니다. BOM을 적용한 빌드가 실패했다는 결과만 확인하게 됩니다.
그래서 릴리스 체크리스트에는 아직 게시되지 않은 아티팩트만 배포하는 원칙을 넣었습니다.
1. 릴리스 버전 행렬을 확정한다.2. 각 상위 BOM 버전이 Central에 있는지 확인한다.3. 이미 게시된 아티팩트는 다시 배포하지 않는다.4. 아직 없는 아티팩트만 상위 저장소의 릴리스 작업으로 배포한다.5. Central 조회를 다시 통과한 뒤 dependencies BOM을 배포한다.이미 있는 버전을 다시 배포하려고 하면 또 다른 문제가 생깁니다. Maven Central의 릴리스 아티팩트는 같은 버전으로 재배포할 수 없습니다. 따라서 아직 없는 아티팩트만 배포해야 합니다. 중복 배포를 CI가 차단할 수는 있지만, 그 동작에 의존하는 대신 운영 절차에서 대상을 먼저 구분해야 합니다.
스냅샷 저장소의 403 오류와 테스트 실패를 구분한다
섹션 제목: “스냅샷 저장소의 403 오류와 테스트 실패를 구분한다”1.3.0 준비 과정에서는 스냅샷을 사용하는 하위 저장소의 워크플로도 정비했습니다.
Maven Central 스냅샷 저장소는 같은 -SNAPSHOT 메타데이터를 짧은 시간에 여러 작업이 동시에 조회할 때 일시적으로
HEAD 403이나 GET 403을 반환하기도 합니다. 이 실패를 테스트 실패와 혼동하면 원인이 다른 문제를 조사하게 됩니다.
따라서 retry-snapshot-resolution.sh는 스냅샷 메타데이터 조회에서 발생한 403 오류 패턴만 재시도합니다.
is_snapshot_resolution_failure() { local log_file="$1" grep -Eiq "Received status code 403|GET 403|HEAD 403" "$log_file" && grep -Eiq \ "central\.sonatype\.com/repository/maven-snapshots|maven-metadata\.xml|Unable to load Maven meta-data|Could not resolve .*SNAPSHOT" \ "$log_file"}기준은 단순합니다. 아무 실패나 재시도하지 않습니다.
재시도한다: Central 스냅샷 메타데이터·아티팩트 403
재시도하지 않는다: 테스트 단언 실패 NoSuchMethodError 스냅샷 404 컴파일 오류이 구분이 없으면 재시도는 장애 완화 도구가 아니라 장애 은폐 도구가 됩니다. 테스트 실패까지 재시도하면 일시적으로 성공할 수는 있어도 원인은 남고, 이후 더 큰 비용으로 이어집니다.
테스트도 이 경계를 고정했습니다.
스냅샷 메타데이터 403 -> 제한적으로 재시도일반 테스트 실패 -> 재시도하지 않고 실패스냅샷 404 -> 재시도하지 않고 실패처음에는 과도해 보일 수 있지만, 릴리스 트레인에서는 실패 유형을 분류하는 코드도 운영 기능입니다. 잘못 분류하면 사람이 잘못된 작업을 하게 됩니다.
버전 카탈로그를 Maven Central 아티팩트로 설명하지 않는다
섹션 제목: “버전 카탈로그를 Maven Central 아티팩트로 설명하지 않는다”1.3.1은 기능 릴리스라기보다 1.3.0 직후 발견한 배포 계약 문제를 정리한 패치 버전이었습니다.
대표적으로 두 가지가 있었습니다.
1. 생성된 POM의 라이선스 메타데이터를 MIT License로 바로잡았다.2. Gradle 버전 카탈로그를 Maven Central 게시물처럼 설명한 릴리스 지침을 고쳤다.두 번째는 실제 사용 경로를 잘못 안내합니다. bluetape4k-dependencies에는 BOM과 catalog가 같이 있습니다.
다만 둘은 배포 경로가 다릅니다.
BOM: io.github.bluetape4k:bluetape4k-dependencies Maven Central에 올라간다.
Catalog: gradle/libs.versions.toml checkout된 git ref 또는 catalog tag에서 읽는다. Maven Central artifact가 아니다.이를 잘못 설명하면 하위 저장소 관리자가 잘못된 위치를 조사하게 됩니다. 카탈로그도 Maven Central에 게시되는지 묻게 된다면 문서가 실제 사용 경로를 충분히 구분하지 못한 것입니다.
라이선스 메타데이터도 마찬가지입니다. 기능 코드가 바뀐 것은 아니지만 공개 아티팩트의 메타데이터는 소비자 도구가 읽습니다. Maven Central에 게시되는 아티팩트라면 라이선스, SCM, 개발자 메타데이터도 릴리스 품질에 포함됩니다.
이런 수정은 변경량만 보면 작습니다. 그러나 사용자 의존성 그래프와 규정 준수 도구에 전달되는 정보라면 신중하게 다뤄야 합니다.
Maven Central에는 롤백 버튼이 없다
섹션 제목: “Maven Central에는 롤백 버튼이 없다”여기까지의 이야기를 한 문장으로 줄이면 이렇습니다.
Maven Central에 게시한 릴리스 버전은 같은 버전으로 교체할 수 없다.예를 들어 1.3.0을 배포한 뒤 POM metadata나 dependency 조합에 문제가 보이면, 같은 1.3.0을 다시 올릴 수 없습니다.
새 버전으로 다시 배포합니다.
1.3.0 배포 -> POM metadata 문제 발견 -> 같은 1.3.0 재배포 불가 -> 1.3.1 배포이 제약 때문에 릴리스 전 검증 절차가 길어집니다.
scripts/sync-managed-catalog.py --check --summaryscripts/verify-managed-artifacts.py --summaryscripts/sync-shared-versions.py --workspace .. --check --summaryscripts/sync-dependabot-ignores.py --workspace .. --check --summary./gradlew build publishToMavenLocal --no-daemon체크리스트가 길면 운영 부담이 생깁니다. 그러나 Maven Central 게시 후 문제를 복구하려면 새 패치 버전과 릴리스 노트, GitHub Release, Central 조회 확인, 하위 저장소 동기화가 모두 필요합니다. 같은 문제를 반복하기에는 비용이 큽니다.
릴리스 트레인은 중앙 BOM을 마지막에 게시한다
섹션 제목: “릴리스 트레인은 중앙 BOM을 마지막에 게시한다”bluetape4k-dependencies는 릴리스 트레인에서 먼저 변경할 것처럼 보이지만, 실제 배포 순서에서는 마지막에 가깝습니다.
1. 상위 저장소별 릴리스 준비2. 상위 저장소별 태그·릴리스·게시3. Maven Central에서 상위 BOM 조회 확인4. dependencies 저장소의 버전 행렬을 릴리스 버전으로 고정5. 관리형 카탈로그, 아티팩트 가용성, 공유 버전 차이 검사6. dependencies BOM 게시7. 워크숍·예제·애플리케이션의 BOM 버전을 올려 확인이 순서가 느려 보여도 이유가 있습니다. 중앙 BOM을 먼저 게시하면 사용자는 유효하지 않은 조합을 받습니다. 중앙 BOM을 마지막에 게시하면 해당 BOM 버전이 게시 시점에 Maven Central에서 조회되는 상위 아티팩트만 참조한다고 보장할 근거가 생깁니다.
여기서도 catalog와 BOM의 역할을 나눠야 합니다.
dependencies BOM: 사용자 의존성 해석 계약 Maven Central 릴리스 아티팩트
dependencies catalog: 여러 bluetape4k 저장소의 빌드 작성 계약 Git 참조·카탈로그 태그 기준하위 워크숍이나 예제는 BOM 버전만 올려 확인합니다. 카탈로그 참조는 유지보수자가 사용하는 도구이고, 애플리케이션의 의존성 사용 계약은 BOM이 담당합니다.
자체 릴리스 트레인에 적용할 점
섹션 제목: “자체 릴리스 트레인에 적용할 점”여러 저장소를 같이 배포한다면, 다음 정도는 자동화하거나 최소한 체크리스트로 고정해 두는 편이 좋습니다.
| 질문 | 확인할 것 |
|---|---|
| 스냅샷 버전 행렬과 릴리스 버전 행렬을 분리했는가? | 다음 개발선의 버전을 이번 안정 릴리스 입력으로 오인하지 않는다. |
| 상위 아티팩트가 Central에서 조회되는가? | BOM이 참조하는 모든 상위 BOM을 HTTP 200 응답 수준으로 확인한다. |
| 이미 배포된 버전을 다시 배포하려 하지 않는가? | 아직 게시되지 않은 아티팩트만 배포한다. |
| 일시적 실패와 결정적 실패를 구분하는가? | 스냅샷 403만 제한적으로 재시도하고 테스트 실패, 404, 바이너리 비호환은 즉시 실패 처리한다. |
| 카탈로그와 BOM을 같은 배포물로 설명하지 않았는가? | BOM은 Maven Central에 게시하고, 카탈로그는 Git 참조 기반의 빌드 작성 계약으로 사용한다. |
publishToMavenLocal로 POM을 확인했는가? | 라이선스, SCM, 스냅샷 참조, 빈 버전을 배포 전에 확인한다. |
| 릴리스 후 소비자 동기화 기준이 있는가? | 워크숍, 예제, 애플리케이션은 검증된 BOM 버전으로 올린다. |
이 표의 목적은 복잡한 자동화를 과시하는 것이 아니라 반복되는 배포 오류를 예방하는 데 있습니다. 실패하더라도 어느 단계에서 어떤 계약이 깨졌는지 즉시 확인할 수 있어야 합니다.
여기까지의 결론
섹션 제목: “여기까지의 결론”bluetape4k-dependencies를 만들면서 배운 건 BOM 자체보다 BOM 주변의 경계였습니다.
- 사용자는 BOM을 가져오고 모듈 버전은 직접 지정하지 않습니다.
- 각 저장소 BOM은 자체 모듈을 책임지고, 중앙 BOM은 하위 BOM을 조합합니다.
- 카탈로그는 유지보수자용 빌드 작성 계약이며 Maven Central 아티팩트가 아닙니다.
- 릴리스 BOM은 스냅샷을 참조하면 안 되며, Central에서 조회되는 상위 아티팩트만 참조해야 합니다.
- Maven Central에 게시한 릴리스 버전은 같은 버전으로 교체할 수 없습니다.
버전 관리 절차는 기능 개발보다 눈에 덜 띄지만, 공개 아티팩트가 깨지면 모든 소비자에게 영향을 줍니다. 게시 전 검증에 시간을 들이는 편이 새 패치 버전과 하위 저장소 동기화를 반복하는 것보다 비용이 낮습니다.
시리즈 글
섹션 제목: “시리즈 글”사용자 관점에서 bluetape4k-dependencies를 가져오는 방법부터 보고 싶다면
사용 가이드를 먼저 읽으면 됩니다.
댓글
GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.