GitHub Packages를 이용해서 나의 패키지를 호스팅하고 GitHub Actions으로 CI/CD 구축하기
공식 문서의 설명이다. 보통 패키지 저장소들은 오픈소스를 올리는 것은 무료지만 개인 패키지는 유료 서비스를 이용하거나 따로 Repository Manager를 구축해야 한다.
GitHub Packages도 공개 패키지의 경우는 무료지만 비공개 패키지의 경우 무료 플랜은 500MB 제한이 있다. 여기에서 각 플랜 별로 제한을 확인할 수 있다.
Gradle 7.6.1 버전으로 진행하였다.
$ mkdir ex-my-pk
$ cd ex-my-pk
$ gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 3
Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6] 3
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 2
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4
Project name (default: ex-my-pk):
Source package (default: ex.my.pk):
> Task :init
Get more help with your project: https://docs.gradle.org/7.6.1/samples/sample_building_java_libraries.html
BUILD SUCCESSFUL in 25s
2 actionable tasks: 2 executed
생성된 Gradle 프로젝트의 구조를 보자.
기본으로 lib
라는 모듈에 Library
라는 클래스가 하나가 생성되어 있고 someLibraryMethod()
라는 메소드가 하나 있다.
빌드 후 성공하면 코드를 깃허브에 올려준다.
루트에 build.gradle.kts
파일을 생성하고 아래와 같이 설정한다.
plugins {
`java-library`
`maven-publish`
}
subprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
group = "ex.my.pk"
version = "1.0.0"
configure<PublishingExtension> {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/hoho4190/ex-my-pk")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
}
publications {
register<MavenPublication>("gpr") {
from(components["java"])
}
}
}
// jar task - manifest 파일에 라이브러리 이름과 버전을 포함
tasks.jar {
manifest {
attributes(mapOf("Implementation-Title" to project.name,
"Implementation-Version" to project.version))
}
}
}
subprojects
에 group
, version
을 적어준다.
<dependency>
<groupId>ex.my.pk</groupId>
<artifactId>lib</artifactId>
<version>1.0.0</version>
</dependency>
implementation("ex.my.pk:lib:1.0.0")
나중에 이런 식으로 디펜던시를 사용할 수 있다.
maven
안에 url
는 uri("https://maven.pkg.github.com/OWNER/REPOSITORY")
처럼 깃허브 아이디와 리파지토리 이름을 적어주면 된다.
USERNAME
, TOKEN
은 환경 변수로 받을 것이다.
lib
모듈의 build.gradle.kts
을 아래와 같이 설정한다.
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.1")
api("org.apache.commons:commons-math3:3.6.1")
implementation("com.google.guava:guava:31.1-jre")
}
tasks.named<Test>("test") {
useJUnitPlatform()
}
java {
withSourcesJar() // 소스 jar 생성
withJavadocJar() // API 문서 추가
}
api
: 이 디펜던시를 소비자에서 내보내진다. 즉, 컴파일 클래스 경로에서 찾을 수 있다.implementation
: 이 디펜던시는 내부적으로 사용되며 자체 컴파일 클래스 경로에서 소비자에게 노출되지 않는다.api
와 implementation
의 자세한 설명은 문서 참고빌드 후 성공하면 코드를 푸시하자.
CI는 GitHub Actions - CI 구축 (Java + Gradle) 참고.
깃허브 리파지토리의 Actions 탭에 들어가서 Publish Java Package with Gradle
를 검색하고 Configure
클릭.
아래와 같이 설정한다.
name: Gradle Package
on:
release:
types: [created] # release가 생성될 때
jobs:
build:
# Workflow가 실행되는 vm의 OS 지정
runs-on: ubuntu-latest
# 권한
permissions:
contents: read
packages: write
steps:
# 1. vm에서 리파지토리를 내려받음
- uses: actions/checkout@v3
# 2. vm에 jdk를 세팅함
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17' # 버전
distribution: 'temurin' # 배포판
server-id: github
settings-path: ${{ github.workspace }}
# 3. gradle build 실행
- name: Build with Gradle
uses: gradle/gradle-build-action@v2.4.2
with:
arguments: build
# 4. gradle publish 실행
# USERNAME, TOKEN 환경 변수에 추가
- name: Publish to GitHub Packages
uses: gradle/gradle-build-action@v2.4.2
with:
arguments: publish
env:
USERNAME: ${{ github.actor }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
딱히 수정할게 없다. 자바 버전이랑 배포판을 맞게 적어주고 gradle-build-action
버전만 바꾸어 주면 된다. 현재 기준 v2.4.2가 최신이다.
이제 release
를 하면 패키지가 자동으로 게시 된다. 확인해보자
우선 리파지토리를 보면 Release
와 Packages
가 없다.
Create a new release
를 클릭하자.
tag는 gradle 프로젝트의 버전과 동일하게 v1.0.0으로 생성하고 제목과 내용을 적고 출시하자.
Actions 탭에 가서 보면 workflow가 실행되고 있을 것이다. 결과를 기다리자.
그리고 리포지토리의 Packages를 보면 자동으로 추가가 되어 있는 것을 확인할 수 있다.
깃허브 계정 > Settings > Developer settings > Personal access tokens > Tokens (classic)에서 개인 토큰을 생성하여 이용하여한다. 필요한 권한은 read:packages
다.
위에서 만든 ex.my.pk
를 사용할 프로젝트에서 아래처럼 설정하자.
repositories {
// ...
maven {
url = uri("https://maven.pkg.github.com/hoho4190/ex-my-pk")
credentials {
username = System.getenv("USERNAME")
password = System.getenv("TOKEN")
}
}
}
dependencies {
// ...
implementation("ex.my.pk:lib:1.0.0")
}
IntelliJ build
설정에서 환경 변수에 USERNAME=xxx;TOKEN=xxx
를 추가해준다.
혹은 명령어로
USERNAME=xxx TOKEN=xxx ./gradlew build
# USERNAME=xxx TOKEN=xxx ./gradlew build --refresh-dependencies
빌드 실행 후
다시 불러오면
ex.my.pk
가 추가된 걸 확인할 수 있다. ex.my.pk
에서 추가한 디펜던시들도 같이 추가된 것을 볼 수 있다.
이제 사용해보자.
api
로 추가한 디펜던시는 사용자도 호출할 수 있지만, implementation
로 추가한 디펜던시는 불가능하다.
개인 리포지토리의 패키지를 팀과 같이 사용하려면 리파지토리를 소유한 개인 또는 조직이 read:packages
권한이 있는 토큰을 공유해줘야 한다.
공개 리포지토리를 패키지를 다른 사람이 사용하려면 사용하려는 사람이 read:packages
권한이 있는 토큰을 만들어서 사용하면 되는거 같다. 공개 리포지토리는 토큰 없이 사용할 수 있을거 같지만 내가 못 찾은 건지 토큰 없이는 불가능한거 같다.