오늘은 1부와 2부에 이어서 마지막 3부를 작성할 예정이다. 이전 포스팅은 여기에서 확인할 수 있다.
1부에서는 기초적인 환경 구축과 Github에서 Push Event가 발생했을 때 트리거해서 Unit Test, Build를 할 수 있도록 Pipeline을 구축했고, 2부에서는 특정 Tag Push를 트리거해서 Firebase App Distribution으로 QA Build를 자동화 배포하도록 구축했다. 그리고 3부에서는 특정 Tag Push를 트리거해서 Google Play Store로 Release Build를 자동화 배포하도록 구축할 예정이다.
본 글에서는 이 자동화 배포를 적용할 Android 프로젝트가 한 번 이상은 Google Play Store에 배포가 된 상태를 전재로 한다. 왜냐하면 처음 앱을 배포할 때 설정해야하는 것들이 있고, 그 다음 배포할 때부터는 APK 파일만 업로드하고 단계적 출시, 출시 노트 등등 몇 개만 설정하고 배포하면 되기 때문이다. Android 프로젝트에 자동화 배포가 구축되면 이 APK 파일 업로드, 출시 노트 설정, 어떠한 등급으로 배포할 것인지에 대해서 자동화할 수 있다.
Jenkins에는 Google Play Store로 배포할 수 있는 Plugin이 존재하지만. 본 글에서는 TripleT
라는 Gradle Plugin을 사용해서 배포할 예정이다. TripleT
Plugin을 사용하면 2부에서 Firebase App Distribution으로 배포할 때 사용했던 방법처럼 Gradle wrapper 명령어를 사용해서 배포할 수 있다.
그리고 이 글에서 구현할 배포 프로세스는 다음과 같다.
QA Build를 통해서 QA Test가 통과되면 Google Play Store로 배포를 준비한다. 자동화 배포를 통해 Unit Test, Build 등을 수행하고 Google Play Console로 배포한다. 그리고 Production 배포 전에 Google Play Store에 Internal Test로 먼저 배포하고 이 Internal Tester로부터 Regression Test를 받는다. 그리고 최종적으로 결함이 없다고 판단된 버전을 Production으로 배포하는 프로세스이다. 위의 단계에서 QA에 대한 부분은 2부에서 이미 구축했고, Google Play Console의 Internal Test로 배포하는 과정이 본 글이 될 예정이다.
Google Play Store
위에서 언급했던 것처럼 본 글에서는 최소 한 번 이상은 배포된 상태를 가정할 예정이다. 혹여 배포를 위한 개발은 끝났지만, 아직 배포하기 전이라면 여기 레퍼런스를 참고하면 좋을 것 같다. 공식 문서는 아니고 앱 제작 서비스를 제공하는 회사에서 Google Play Store 배포에 대해서 잘 정리해준 글이다.
작업 순서는 다음과 같다.
Triplet
설정하기
1. GCP의 서비스 계정 만들고 권한 설정하기
Google Play Console에서 좌측 하단 설정
> API 액세스
를 클릭하고, 새 서비스 계정 만들기에 들어간다. 그러면 아래의 사진과 같이 팝업 창이 뜰 것이다.
위의 순서대로 따라하면 된다. 먼저 1번으로 이동해서 GCP로 이동한다. 그러면 아래의 사진과 같이 Google Play Console Developer로 설정된 화면으로 이동되는데, 이 화면에서 상단의 서비스 계정 만들기를 클릭한다. 참고로 이 서비스 계정은 2부에서 작업했던 Firebase App Distribution에서 사용되는 서비스 계정과는 다른 계정이다.
그리고 아래의 사진과 같이 입력한다. XXXX는 본인 프로젝트의 이름으로하면 좋을 것 같다.
그리고 '만들고 계속하기'를 클릭한 후 권한을 소유자
로 설정한다. 그리고 계속
을 클릭한 후 완료
버튼을 통해 서비스 계정을 생성한다. 그 다음 방금 생성한 서비스 계정의 이메일 부분을 클릭해서 상세 화면으로 이동한 후 아래의 사진과 같이 키 탭으로 이동한 후에 키 추가
> 새 키 만들기
> JSON
선택 > 만들기
버튼을 클릭한다.
그러면 json 파일이 다운로드 될 것이다. 이 파일의 이름을 google-play.json
으로 변경하고 firebase 연동할 때 Andorid 프로젝트에 저장했던 google-service.json
파일의 위치와 동일한 곳에 저장하면 된다. 그리고 다시 Google Play Console 화면의 팝업 안내 창으로 돌아온 후 완료 버튼을 클릭한다. 그러면 방금 GCP에서 만들었던 이메일 이름과 함께 오른쪽에 권한보기 버튼이 보일 것이다. 이 권한보기를 클릭한다.
(혹여 바로 안 보인다면 서비스 계정 새로고침 버튼을 통해 여러번 새로고침 해본다.)
그리고 앱 권한 탭 아래에 Android 프로젝트 앱이 보일 텐데, 오른쪽의 권한 관리를 클릭한 다음, 관리자(모든 권한)을 체크한 뒤 적용 버튼을 통해서 권한하고 변경사항 저장을 통해 서비스 계정 설정을 마무리한다.
2. TripleT 설정하기
Android 프로젝트 안에 TripleT plugin을 설정해야 한다. 먼저 아래와 같이 build.gradle(:project)
파일에서 buildscript
> dependencies
안에 classpath를 설정해준다.
classpath 'com.github.triplet.gradle:play-publisher:3.5.0'
그리고 build.gradle(:app)
파일에서 아래의 사진과 같이 Plugin을 설정한다.
그리고 동일한 build.gradle(:app)
파일 안에서 아래의 사진처럼 설정하는데, 위치는 딱히 상관 없지만 android scope나 dependencies scope, plugins scope에 포함되지 않도록 주의한다.
serviceAccountCredentials
는 1번 과정에서 저장했던 서비스 계정의 json 키 파일이다. 그리고 track
은 Google Play Console에서 Internal Test로 배포하도록 지정한 설정이다. 더 다양한 옵션과 자세한 설명은 여기에서 참고하면 좋을 것 같다.
3. 출시 노트 설정하기
이제 TripleT
를 사용하면 아래의 사진과 같은 출시 노트 입력창 안에 자동으로 내용이 들어가도록 설정할 수 있다.
위의 사진처럼 직접 출시 노트를 작성하지 않아도 Android 프로젝트에서 특정 txt 파일에 내용을 입력하면 위의 입력창에 자동으로 입력된다. 아래의 경로 안에 txt 파일을 만들면 되고 경로에 따라서 언어별로 지정할 수 있다.
src/main/play/release-notes/kr-KR/internal.txt
txt 파일의 이름은 어느 트랙에 배포할지 선택하면 된다. 본 글의 배포 프로세스에서는 internal로 배포할 예정이니까 internal.txt
로 지정했다. 이 파일은 최종적으로 릴리즈 배포가 준비되면 versionName
과 versionCode
를 변경하는 시점에 같이 출시 노트를 업데이트하면 된다. 그리고 이 변경한 commit에 Tag Push하면 Jenkins가 이를 갖고 자동화 배포를 진행한다.
4. Pipeline 구성하기
Jenkins의 Multibranch Pipeline 설정은 여기 2부에서 자세히 확인할 수 있고, 이 3부에서는 Multibranch Pipeline에 대한 설정 설명은 생략할 예정이다. 그리고 2부에서 작성한 Script에 이어서 아래와 같이 작성할 예정이다.
pipeline {
agent any
options {
skipStagesAfterUnstable()
}
tools {
jdk('JAVA8')
}
environment {
// Build Variant에 대해서 설정했다면 어떤 Variant로 Delpoy할 지 선택하기.
BUILD_VARIANT_FOR_QA = "Debug" // "DevAlpha"
BUILD_VARIANT_FOR_RELEASE = "Release" // "ProductRelease"
}
stages {
stage("Environment") {
steps {
script {
//withCredentials([string(credentialsId: "build-pwd", variable: "PWD")]) {
// env.DevKeyPassword = "${PWD}"
// env.DevStorePassword = "${PWD}"
// env.ProductKeyPassword = "${PWD}"
// env.ProductStorePassword = "${PWD}"
//}
}
}
}
// 아래 stage와 94~100번째 코드는 참고용. 지워도 무관.
//stage("Get app version") {
// steps {
// script {
// def data = readFile(file: 'version.properties')
// env.VERSION_CODE = getVersionCode(data)
// env.VERSION_NAME = getVersionName(data)
//
// sh "echo VERSION_CODE: ${env.VERSION_CODE} VERSION_NAME: ${env.VERSION_NAME}"
// }
// }
//}
stage("QA Unit Test") {
when {
tag "qa/*"
}
steps {
sh "./gradlew test${env.BUILD_VARIANT_FOR_QA}UnitTest --stacktrace"
junit "**/TEST-*.xml"
}
}
stage("QA Deploy") {
when {
tag "qa/*"
}
steps {
echo "Start Deploying to Firebase.."
sh "./gradlew assemble${env.BUILD_VARIANT_FOR_QA} appDistributionUpload${env.BUILD_VARIANT_FOR_QA} --stacktrace"
archiveArtifacts artifacts: "**/*.apk, **/mapping.txt", fingerprint: true
}
}
stage("Release Unit Test") {
when {
tag "release/*"
}
steps {
sh "./gradlew test${env.BUILD_VARIANT_FOR_RELEASE }UnitTest --stacktrace"
junit "**/TEST-*.xml"
}
}
stage("Release Deploy") {
when {
tag "release/*"
}
steps {
echo "Start Deploying to Google Play.."
sh "./gradlew publish${env.BUILD_VARIANT_FOR_RELEASE}Bundle --stacktrace"
archiveArtifacts artifacts: "**/*.apk, **/mapping.txt", fingerprint: true
}
}
}
//def getVersionCode(String body) {
// return (body =~ /VERSION_CODE\s*=\s*(\d+)/)[0][1]
//}
//def getVersionName(String body) {
// return (body =~ /VERSION_NAME\s*=\s*(\d+\.\d+\.\d+(\.\d+)?)/)[0][1]
//}
위의 주석에 대한 설명과 그 외의 자세한 설명은 2부의 내용을 참고하면 좋을 것 같다. 그러나 이 3부에서 추가된 내용은 87~88번째 줄 단 2줄이다. 2번 과정에서 TripleT
라는 Gradle Plugin을 추가해주었기 때문에 87번째 줄인 publish{Build Variant}Bundle
명령어를 실행할 수 있다. 그리고 이 명령어를 입력하면 TripleT
의 설정 옵션에 따라서 Google Play Store로 자동 배포가 된다.
그리고 예를 들어 release/1.1.3
Tag를 생성하고 Push하면 아래의 사진처럼 내부테스트에 등록이 될 것이다.
그리고 Internal Tester에 의해 Regression Test가 완료되면 위의 사진처럼 프로덕션으로 승급하고 최종적으로 Google Play 측에 앱 검토 요청을 할 수 있다. 이후 검토가 완료되면 사용자들에게 새롭게 출시된 버전이 Google Play Store에 노출된다.
이상 3부를 마지막으로 Android를 위한 Jenkins CI/CD에 대해서 마무리하려 한다. 1부, 2부, 3부에 걸쳐서 Jenkins 기본 환경 구축 및 Github Repository에서 Push Event가 발생할 때마다 UnitTest - Build를 수행하고 결과를 Github에 표시하도록 구축했다. 그리고 특정 Tag Push를 통해서 QA Build를 Firebase App Distribution으로 배포하고, 특정 Tag Push를 통해서 Release Build를 Google Play Store로 배포하는 방법에 대해서 정리했다.