포스트

Maven Central Repository에 자바 라이브러리 배포

우리가 프로젝트를 개발할 때, 필요한 라이브러리들을 외부 저장소에서 다운로드하여 의존성으로 사용한다. 이는 groupId, artifactId, version으로 구분된다.

Maven Central Repository에 자바 라이브러리 배포

우리가 프로젝트를 개발할 때, 필요한 라이브러리들을 외부 저장소에서 다운로드하여 의존성으로 사용한다.

이는 groupId, artifactId, version으로 구분되는데, 위 사진의 swagger를 기준으로 설명 가능하다. groupId : org.springdoc artifactId : springdoc-openapi-starter-webmvc-ui version : 2.0.2

이러한 방식으로 Maven Central Repository와 같은 저장소에 존재하는 라이브러리를 groupId, artifactId, version을 합친 좌표를 통해 의존성으로 추가할 수 있다.

나아가, 외부의 저장소에 직접 개발한 라이브러리도 배포하여 모든 사람들이 사용하도록 할 수 있다.

Maven Central Repository에 라이브러리 배포

Maven Central Repository는 의존성 관리의 중심 저장소로서, 전 세계 개발자들이 사용하는 공식 라이브러리 저장소이다. Spring, Lombok, Junit 등 다양한 라이브러리가 등록되어있으며, groupId:artifactId:version만 알면 언제든지 다운로드 가능하다.

group id 등록

Maven Central Repository Maven Central Repository사이트에 회원가입을 진행한다.

먼저, 소유한 도메인에 대한 namespace 인증이 필요하다. 배포시 사용할 groupId를 생성하는 절차이다.

View Namespace메뉴로 들어가 Namespace를 등록한다.

다음과 같이 reverse-DNS형식으로 등록할 수 있으며, Verify Namespace를 통해 검증을 진행한다. 만약 naver.com이라는 도메인을 소유 시, namespace로 com.naver를 등록할 수 있는 것이다.

도메인을 가지고 있지 않다면 깃허브계정을 기반으로도 namespace 등록이 가능하다. io.github.{githubId}를 통해 namespace를 생성할 수 있다.

깃허브로 namespace생성 시, 위 사진과 같이 Verification Key를 이름으로한 public 리포지토리를 생성하여 인증을 진행한다.

잠시 후, 인증이 완료됨을 확인할 수 있다.

GPG 서명

이제 maven central repository에 라이브러리를 배포하기 위해선, gpg 서명이 필수적이다. 배포된 라이브러리의 위변조를 방지하기 위함이다.

gpg키를 생성하는 무료 패키지 gnupg를 설치하여 사용 가능하다.

1
brew install gnupg

gpg 공개키 생성

1
gpg --gen-key

위 명령어를 실행하여 Real Name, Email을 입력한다.

그 후, passphrase(password)를 입력한다.

다음과 같이 공개 키가 생성된다.

공개 키 전송

Maven Central Repository가 서명을 검증할 때 공개 키로 서명이 유효한지 확인할 수 있도록, 키 서버에 해당 공개 키를 전송해야한다.

keyserver.ubuntu.com keys.openpgp.org pgp.mit.edu

다음 중 하나의 키 서버에 전송하면 되지만, 필자는 keyserver.ubuntu.com서버에 전송이 되지 않아 두 번째 서버에 공개 키를 전송했다.

1
gpg --keyserver hkps://keys.openpgp.org --send-keys {public-key}

해당 명령어를 사용하면 된다.

비밀 키 설정

원래대로라면,

1
gpg --keyring secring.gpg --export-secret-keys > ~/.gnupg/secring.gpg

다음과 같은 비밀키를 내보내는 방식도 사용해야 하지만, gradle의 비공식 플러그인인 vanniktech/gradle-maven-publish-plugin을 사용하여 자동으로 비밀키를 설정할 예정이다.

build.gradle 설정

gradle-maven-publish-plugin-central-docs 해당 플러그인 문서를 참조하여 build.gradle을 작성하였다.

본인의 프로젝트는 2개의 서브 라이브러리를 두며, 하나는 바닐라 자바, 나머지 하나는 Spring Boot를 의존성으로 두개에 각각의 서브 라이브러리를 build.gradle로 각각 배포해야한다.

gradle.properties

먼저, gradle.properties파일을 루트 디렉토리에 만든다.

1
2
3
4
5
6
mavenCentralUsername={username}
mavenCentralPassword={password}
  
signing.gnupg.keyName={public_key}
signing.gnupg.passphrase={passphrase} 
signing.gnupg.useGpgCmd=true

mavenCentralUsername과 password는 maven central repository 사이트에서 생성해야한다. view account » generate user token에서 생성 가능하다.

위 사진과 같이 username과 password가 생성되는데, 이를 gradle.properties에 복사한다. 한번 생성되면 다시는 생성되지 않으므로 주의해야한다.

signing.gnupg.keyNamesigning.gnupg.passphrase는 이전에 생성한 공개키 정보를 입력하고, signing.gnupg.useGpgCmd는 비밀키 설정을 자동으로 설정하는 옵션이므로 True로 설정한다.

build.gradle (root)

루트 프로젝트의 build.gradle의 주요 설정이다.

1
2
3
4
5
6
7
8
9
allprojects {  
    group = 'io.github.yyytir777'  
    version = "0.0.2"  
  
    java {  
        toolchain {  
            languageVersion.set(JavaLanguageVersion.of(17))  
        }  
    }}

allproject로 group과 version을 명시하였다. 후에 subproject의 build.gradle에서 group과 version을 변수로서 사용할 수 있다.

build.gradle (sub)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
plugins {
    id 'java-library'
    id "com.vanniktech.maven.publish" version "0.34.0"
    id 'signing'
}

signing {
    useGpgCmd()
    sign publishing.publications
}

mavenPublishing {
    publishToMavenCentral()
    signAllPublications()
    coordinates(group.toString(), "your-artifact-id", version.toString())

    pom {
        name = "Your Library Name"
        description = "Description of your library"
        inceptionYear = "2025"
        url = "https://github.com/your-username/your-repo"
        licenses {
            license {
                name = "The MIT License"
                url = "https://opensource.org/licenses/MIT"
            }
        }

        developers {
            developer {
                id = "your-id"
                name = "Your Name"
                url = "https://github.com/your-username"
            }
        }
        scm {
            url = "https://github.com/your-username/your-repo"
            connection = "scm:git:git://github.com/your-username/your-repo.git"
            developerConnection = "scm:git:ssh://git@github.com/your-username/your-repo.git"
        }
    }
}

이와 같이 설정하였다. spring boot에 의존하는 라이브러리를 배포할 경우, Spring Boot 플러그인이 생성하는 실행용 빌드 (bootJar)는 제외하고 일반적인 .jar만 배포하도록 아래 설정을 추가해야한다.

1
2
3
4
5
6
7
tasks.named("bootJar") {
	enabled = false
}

tasks.named("jar") {
	enalbed = true
}

gradle 배포

1
./gradlew publishAllPublicationsToMavenCentralRepository

다음 명령어를 통해 배포할 수 있다.

아래와 같이 배포됨을 확인할 수 있다. 이때 Drop을 누르면 삭제되고, Publish를 누르면 Maven 저장소에 올라가 절대 삭제할 수 없으므로 주의해야한다.

이슈

서브 라이브러리 2개를 maven 저장소에 배포하였다. 하나는 바닐라 Java 라이브러리였고, 나머지 하나는 Spring Boot를 의존성으로 가진 라이브러리였다.

다음과 같이 spring boot의존성을 가진 Components에 type=pom이라는 문구가 추가되어 총 3개가 배포됨을 확인하였다.

Maven에 배포할 때 필수로 올라가야하는 파일은 다음과 같다.

{library_name}-{version}.jar

실제 라이브러리 바이트코드가 들어있는 기본 아티펙트

{library_name}-{version}.pom

의존성, 라이선스 등의 메타데이터가 들어있는 파일

{library_name}-{version}-sources.jar

소스 코드 포함 아티펙트

{library_name}-{version}-javadoc.jar

Javadoc 포함 아티펙트

다음과 같은데, {library-name}-{version}.jar 형태의 파일이 없으면 POM only artifact로 처리하기 때문에 위와 같은 상황이 발생한 것이다.

즉, {library-name}-{version}-plain.jar 형태의 아티펙트가 업로드 되었기 때문에 이를 인식하지 못하고 해당 라이브러리를 POM Only artifact로 인식하였다.

1
2
3
tasks.named("jar") {
    archiveClassifier.set("")
}

다음과 같이 build.gradle을 설정하면 plain이 붙지 않는 정상적인 아티펙트를 생성할 수 있다.

이후 다시 maven 배포를 진행하면

이와 같이 정상적으로 아티펙트를 인식함을 확인할 수 있다.


원문: Velog

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.