Kotlin, Spring 기반의 오픈소스 라이브러리를 만들었습니다. Spring REST Docs를 사용하신다면 한번 사용해보시는 걸 추천드립니다.
GitHub - cares0/rest-docs-kdsl: Simplify Spring REST Docs with Kotlin DSL
Simplify Spring REST Docs with Kotlin DSL. Contribute to cares0/rest-docs-kdsl development by creating an account on GitHub.
github.com
Maven과 Maven Central Repository
Maven은 JVM 기반 프로젝트의 빌드 도구이다. 프로젝트가 의존하는 모든 라이브러리을 가져오고, 프로젝트를 컴파일, 테스트, 패키징 하여 배포까지 자동으로 처리할 수 있도록 도와준다.
Maven의 주요 기능 중 하나는 프로젝트의 의존성을 관리하는 것이다. 프로젝트가 의존하고 있는 라이브러리를 아티팩트가 저장되어 있는 외부 리포지토리로부터 가져와 쉽게 사용할 수 있게 해준다.
여기서 Maven Central Repository는 외부 리포지토리 중 하나이며 Maven Comunnity에서 제공된다. 외부 리포지토리 중 가장 많은 아티팩트가 저장되어 있는 저장소이기도 하다. (우리가 외부 라이브러리를 사용하기 위해 자주 방문하는 MVN Repository 사이트에 들어가보면, 오른쪽에 Indexed Repository 메뉴가 보이는데 아래에 리스트업된 것들이 외부 리포지토리의 한 종류에 해당된다.)
따라서 이번 포스팅에서는 Maven Central Repository에 오픈소스를 배포하는 방법을 기술할 것이다.
이전에는 Apache 재단이 아닌 개인이나 회사에서 오픈소스를 만드는 경우에 OSSRH(Open Source Software Repository Hosting) 방식을 통해 Maven Central Repository에 배포할 수 있었다. 하지만 2024년 3월 12일부터 신규로 등록하는 경우 OSSRH 방식에서 Central Portal에 직접 등록하는 방식으로 변경되었기 때문에 이 방식을 다뤄볼 것이다.
Maven Central 계정 설정
계정 생성
Maven Central
Official search by the maintainers of Maven Central Repository.
central.sonatype.com
Maven Central 사이트에 들어가서 가입을 진행하자.
Namespace 등록
계정을 생성한 후 우측 상단에 계정 이름을 클릭하여 View Namespaces 메뉴를 클릭해보자.
그러면 Publish Settings 페이지가 뜨는데, 여기서 등록된 Namespace를 확인할 수 있다. Github 계정을 통해 가입하는 경우 자동으로 검증된 Github Namespace가 등록된다. 아니라면 Add Namespace 버튼을 클릭하여 추가해야 한다.
Namespace는 Java, Kotlin 프로젝트의 패키지 명 처럼 reverse-DNS 형식으로 입력해야 한다.
등록하고 나면 위와 같이 뜬다. 왼쪽 하단에 Verification Key가 있는데 이를 통해 검증할 수 있다.
깃허브와 같은 Code Hosting Services를 Namespace로 등록한 경우에는 Verification Key를 리포지토리 이름으로 해서 생성하면 검증할 수 있다. Github의 리포지토리 경로를 보면, 경로변수에 리포지토리명이 들어가 있는 형식인데 경로변수에 Verification Key값이 들어가도록 하면 된다.
만약 개인 도메인으로 등록한 경우에는 DNS TXT 레코드를 추가하여 검증할 수 있다. 문서를 확인해보자.
일정 시간이 지나도 검증이 진행되지 않는다면, 카드 우측 상단에서 View History를 클릭하여 검증 이력을 확인해 조치를 취하면 된다.
Central Portal 유저 토큰 생성
우측 상단에 View Account 메뉴를 클릭하자.
Generate User Token 버튼을 클릭하여 토큰을 생성하면 된다.
그럼 위와 같이 Username, Password가 생성되는데 나중에 배포할 때 필요하기 때문에 어딘가에 기록해두자.
배포
Maven Central Repository에 아티팩트를 배포하기 위해서는 필요한 요건이 있다.
1. source.jar, javadoc.jar를 제공해야 한다.
2. 배포되는 모든 파일에는 체크섬 파일이 포함되어야 한다.
3. 배포되는 모든 파일은 GPG/PGP로 서명해야 한다.
4. 메타데이터를 pom 파일에 제출해야 한다.
- Coordinate(GAV): groupId, artifactId, version
- Project Name
- Project Description
- Project URL
- License Information
- Developer Information
- SCM Information
요건이 꽤 많아보이는데, 사실 별거 없다.
이 포스팅에서는 Gradle 프로젝트에 대해 배포를 할 것인데, 일일이 pom을 작성하지 않고 플러그인 스크립트만 적당히 작성해주면 위 요건을 맞도록 자동으로 빌드해준다.
만약 Maven으로 빌드되는 프로젝트라면 이 문서를 참고하자.
배포 스크립트 작성
Gradle 플러그인을 사용해서 배포를 할 것이다. 사용할 플러그인은 vanniktech/gradle-maven-publish-plugin 이다.
배포하려는 프로젝트의 `build.gradle.kts`에 아래 스크립트 복사해서 배포할 프로젝트에 맞게 수정해보자.
plugins {
id("com.vanniktech.maven.publish") version "0.29.0"
}
mavenPublishing {
coordinates( // Coordinate(GAV)
groupId = "io.github.cares0",
artifactId = "rest-docs-kdsl-ksp",
version = "1.0.4"
)
pom {
name.set("rest-docs-kdsl") // Project Name
description.set("Simplify Spring REST Docs with Kotlin DSL") // Project Description
inceptionYear.set("2024") // 개시년도
url.set("https://github.com/cares0/rest-docs-kdsl") // Project URL
licenses { // License Information
license {
name.set("The Apache License, Version 2.0")
url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers { // Developer Information
developer {
id.set("cares0")
name.set("YoungJun Kim")
email.set("cares00000@gmail.com")
}
}
scm { // SCM Information
connection.set("scm:git:git://github.com/cares0/rest-docs-kdsl.git")
developerConnection.set("scm:git:ssh://github.com/cares0/rest-docs-kdsl.git")
url.set("https://github.com/cares0/rest-docs-kdsl.git")
}
}
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
signAllPublications() // GPG/PGP 서명
}
스크립트를 잘 보면, 위에 나열했던 요건들에 대한 정보가 모두 들어가 있다. 그냥 이대로 작성만해주면 플러그인에서 알아서 pom 파일을 만들어준다.
필자는 Gradle 멀티 모듈 프로젝트를 구성하여 배포했는데, Maven Repository에 배포되어 있지 않은, 개인이 만든 모듈을 사용하는 경우 해당 모듈까지 Maven Repository에 배포를 해야 한다. 만약 core 모듈이 있고 이를 의존하는 ksp 모듈이 있다면 두 모듈 모두 위의 스크립트를 작성해야 한다.
GPG/PGP 설정
PGP는 공개키 방식으로 파일을 암호화 하는 프로그램인데, 현재 유료로 사용할 수 있다. 하지만 대용으로 OpenPGP 표준을 구현한 GnuPG를 통해 무료로 사용할 수 있다.
GnuPG 설치
GnuPG - Download
Note that you may also download the GNU Privacy Guard from a mirror site close to you. See our list of mirrors. The table below provides links to the location of the files on the primary server only. These are the canonical release forms of GnuPG. To use t
www.gnupg.org
위 사이트에 들어가서 OS에 맞게 다운로드를 해주면 된다. 필자는 Mac을 사용하고 있어서 brew를 통해 다운받았다.
brew install gnupg
GPG키 생성
이제 GPG 키를 생성해보자.
gpg --full-gen-key
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(14) Existing key from card
Your selection? 1
RSA and RSA 를 선택해주면 된다. 이후에 Key bits는 4096으로, 만료 기한, 이름, 이메일, 커멘트는 본인에게 맞는 값으로 입력해주자. 이름, 이메일은 추후 아티팩트 배포 시 다른 사람들이 확인할 수 있기에 필수로 제공해야 한다.
모두 입력이 끝나고 확인을 하면 비밀번호를 설정하는 창이 뜨는데, 동일한 비밀번호를 두 번 입력해주면 된다.
pub rsa4096 발행일 [SC] [expires: 만료일]
GPG 공개키
uid 이름 (커멘트) <이메일>
sub rsa4096 발행일 [E] [expires: 만료일]
그럼 위와 같이 키 정보가 표시된다. 발급된 키 정보는 `gpg --list-keys`를 통해서도 조회할 수 있다.
공개키 배포
이제 다른 사람들이 배포 파일을 검증하기 위해 사용할 수 있기 때문에, GPG키 서버에 공개키를 배포해야 한다. GPG 키 서버로는 아래 서버들이 있다.
- keyserver.ubuntu.com
- keys.openpgp.orgp
- gp.mit.edu
gpg --keyserver keyserver.ubuntu.com --send-keys GPG공개키
배포하려는 서버를 명시한 후, GPG 공개키를 입력하자. 공개키 마지막 8자리만 입력해도 된다.
비밀키 내보내기
gpg --keyring secring.gpg --export-secret-keys > ~/.gnupg/secring.gpg
위 커맨드를 실행하여 비밀키를 내보내자. 추후 배포 시 사용된다.
배포 설정 추가
지금까지 설정했던 키들을 `gradle.properties`에 넣어줄 것이다.
// Central Portal 유저 토큰 정보
mavenCentralUsername= // Central Portal Username
mavenCentralPassword= // Central Portal Password
// GPG Key
signing.keyId= //GPG 공개키 뒤 8자리
signing.password= //GPG 비밀번호
signing.secretKeyRingFile= //비밀키 경로, Mac의 경우 /Users/Mac유저이름/.gnupg/secring.gpg
앞에서 Central Portal의 유저 토큰을 만들었었는데, username과 password 값을 입력해주면 된다.
GPG keyId는 는 키 뒤 8자리를 기입하고, password는 키 생성시에 2번 입력했던 비밀번호 값을 넣어주면 된다. 비밀키 경로는 앞에서 내보내기 했을 때의 경로를 넣어주면 된다.
입력한 정보들은 외부에 노출되면 안되는 정보이기 때문에 깃허브에 올라가지 않도록 주의하자. 만약 Git Action과 같은 CI/CD 도구에서 배포 파이프라인을 만드는 경우에는 해당 값을 Secrets에 등록하는 것을 권장한다.
Maven Central Repository에 배포하기
이전에`build.gradle.kts`에 배포 스크립트를 작성했다면, 실행 가능한 커맨드가 생긴다.
한번 `./gradlew publishAllPublicationsToMavenCentralRepository` 커맨드를 실행시켜보자. 위해서 했던 설정을 모두 잘 했다면 문제없이 진행될 것이다.
완료가 되었다면 Maven Central 페이지에 들어가서 우측 상단에 View Deployments 메뉴를 클릭하자.
이렇게 PENDING 상태를 거친 다음
VALIDATED 상태로 변경된다. 컴포넌트들에 대한 정보들을 볼 수 있고, 여기서 Publish를 누르면 바로 Maven Central Repository에 아티팩트가 배포되게 된다.
단, 한번 배포된 아티팩트는 절대로 수정하거나 삭제하지 못한다. 이유는 당연한데, Maven Central Repository에 아티팩트가 올라가면 이제 모든 사람들이 해당 아티팩트에 포함된 라이브러리를 자신의 프로젝트에서 사용할 수 있게 된다. 그런데 갑자기 사용하고 있는 라이브러리 코드가 변경되었다고 해보자. 해당 라이브러리를 사용하던 프로젝트는 수정된 코드로 인해 갑자기 예상치 못한 오류가 발생할 수 있을 것이다. 이러한 이유로 한번 배포된 아티팩트는 절대 수정하거나 삭제하지 못하니 항상 Publish 버튼은 주의해서 사용해야 한다.
만약 이미 Maven Central Repository에 있는 동일한 아티팩트를 배포하는 경우 등 문제가 있는 경우에는 FAILED 상태로 표시된다.
Maven Local Repository에 배포하기
만약 Maven Central Repository에 배포하기 전에, 외부에서 제대로 동작하는지 확인하려면 어떻게 해야 할까? 한번 배포된 아티팩트는 절대로 수정할 수 없기 때문에, 버전을 바꿔가며 배포하는 것도 하나의 방법이겠지만 그리 좋은 방법은 아니다.
배포된 아티팩트는 MVN Repository와 같은 리포지토리 인덱싱 사이트에서 외부 사용자들에게 검색될 수 있다. 문서에 사용 가능한 버전을 명시해두었다고 해도, 정상적으로 동작하지 않는 아티팩트가 배포된 경우 실수든 어떤 이유로든 외부 사용자가 사용할 수 있게 된다.
이런 경우 Maven Local Repository에 배포하여 테스트 해보는 것이 좋다. 이는 실제 외부 저장소가 아니라, 자신의 로컬 디바이스 내부에 아티팩트를 배포하기 때문에 외부 사용자가 접근할 수 없다.
./gradlew publishToMavenLocal
위 커맨드를 한번 실행시켜보자. 그리고 자신의 디바이스에서 Maven Local Repository를 찾아보자. 대게 `.m2`라는 이름으로 지정되어 있다. 배포한 프로젝트의 GAV 경로를 따라가보면 배포한 라이브러리가 보인다.
사용하는 곳에서는 동일하게 빌드 스크립트에 의존성을 추가하여 사용할 수 있다.
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation("io.github.cares0:rest-docs-kdsl-ksp:1.0.5")
}
다만 Maven을 쓰든 Gradle을 쓰든, Maven Local 리포지토리에서 가져올 수 있도록 리포지토리를 추가해야 한다.