# Zellyy Finance CI/CD 파이프라인 가이드 이 문서는 Zellyy Finance 앱의 CI/CD(지속적 통합/지속적 배포) 파이프라인 구축 및 사용 방법에 대해 설명합니다. ## 목차 1. [개요](#개요) 2. [CI/CD 파이프라인 구성](#cicd-파이프라인-구성) 3. [GitHub Actions 설정](#github-actions-설정) 4. [버전 관리 자동화](#버전-관리-자동화) 5. [테스트 빌드 배포 및 설치](#테스트-빌드-배포-및-설치) 6. [앱스토어 자동 배포](#앱스토어-자동-배포) 7. [비용 분석](#비용-분석) 8. [문제 해결 및 FAQ](#문제-해결-및-faq) ## 개요 CI/CD 파이프라인은 코드 변경사항을 자동으로 빌드, 테스트 및 배포하는 자동화된 프로세스입니다. Zellyy Finance 앱에서는 GitHub Actions를 사용하여 이 프로세스를 구현합니다. ### 주요 이점 - **개발 효율성 향상**: 반복적인 빌드 및 배포 작업 자동화 - **일관된 빌드 품질**: 동일한 환경에서 항상 일관된 방식으로 빌드 - **버전 관리 자동화**: 버전 코드 및 빌드 번호 자동 증가 - **배포 프로세스 간소화**: 앱스토어 제출 과정 자동화 - **팀 협업 개선**: 빌드 상태 및 결과 공유 용이 ## CI/CD 파이프라인 구성 Zellyy Finance의 CI/CD 파이프라인은 다음과 같은 단계로 구성됩니다: 1. **코드 검증**: 린트 검사 및 단위 테스트 실행 2. **웹 앱 빌드**: React 앱 빌드 3. **네이티브 앱 빌드**: Capacitor를 통한 Android/iOS 앱 빌드 4. **테스트 배포**: Firebase App Distribution을 통한 테스터 배포 5. **앱스토어 배포**: Google Play Store 및 Apple App Store 배포 ### 워크플로우 다이어그램 ``` 코드 푸시/PR → 코드 검증 → 웹 앱 빌드 → 네이티브 앱 빌드 → 테스트 배포 → 앱스토어 배포 ``` ## GitHub Actions 설정 ### 워크플로우 파일 생성 `.github/workflows/ci-cd.yml` 파일을 생성하여 CI/CD 파이프라인을 구성합니다. ```yaml name: Zellyy Finance CI/CD on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] workflow_dispatch: inputs: buildType: description: '빌드 타입 (debug, release-apk, release-aab, ios-release)' required: true default: 'debug' versionCode: description: '버전 코드 (자동 증가는 1, 수동 지정은 원하는 숫자 입력)' required: false versionName: description: '버전 이름 (예: 1.0.0)' required: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 노드 설정 uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: 종속성 설치 run: npm ci - name: 린트 검사 run: npm run lint - name: 버전 정보 설정 id: version run: | # 현재 버전 코드 가져오기 CURRENT_VERSION_CODE=$(grep -o 'versionCode [0-9]*' android/app/build.gradle | awk '{print $2}') if [ -z "$CURRENT_VERSION_CODE" ]; then CURRENT_VERSION_CODE=1 fi # 현재 버전 이름 가져오기 CURRENT_VERSION_NAME=$(grep -o 'versionName "[^"]*"' android/app/build.gradle | sed 's/versionName "//' | sed 's/"//') if [ -z "$CURRENT_VERSION_NAME" ]; then CURRENT_VERSION_NAME="1.0.0" fi # 입력된 버전 정보 또는 기본값 사용 if [ "${{ github.event.inputs.versionCode }}" = "1" ] || [ -z "${{ github.event.inputs.versionCode }}" ]; then NEW_VERSION_CODE=$((CURRENT_VERSION_CODE + 1)) else NEW_VERSION_CODE=${{ github.event.inputs.versionCode }} fi VERSION_NAME="${{ github.event.inputs.versionName }}" if [ -z "$VERSION_NAME" ]; then VERSION_NAME=$CURRENT_VERSION_NAME fi BUILD_NUMBER=$NEW_VERSION_CODE # 버전 정보 파일 업데이트 echo "buildNumber=$BUILD_NUMBER" > android/version.properties echo "versionCode=$NEW_VERSION_CODE" >> android/version.properties echo "versionName=$VERSION_NAME" >> android/version.properties cp android/version.properties android/app/version.properties # app_version.json 파일 업데이트 cat > android/app_version.json << EOF { "versionCode": $NEW_VERSION_CODE, "versionName": "$VERSION_NAME", "buildNumber": $BUILD_NUMBER, "notes": "자동 빌드에 의해 생성된 버전 정보입니다." } EOF echo "VERSION_CODE=$NEW_VERSION_CODE" >> $GITHUB_OUTPUT echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_OUTPUT echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_OUTPUT - name: 웹 앱 빌드 run: npm run build - name: Capacitor 동기화 run: npx cap sync android - name: JDK 설정 uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' cache: 'gradle' - name: 안드로이드 앱 빌드 working-directory: android run: | if [ "${{ github.event.inputs.buildType }}" = "release-aab" ]; then ./gradlew clean bundleRelease elif [ "${{ github.event.inputs.buildType }}" = "release-apk" ]; then ./gradlew clean assembleRelease else ./gradlew clean assembleDebug fi - name: Firebase App Distribution 배포 if: github.event.inputs.buildType == 'debug' uses: wzieba/Firebase-Distribution-Github-Action@v1 with: appId: ${{ secrets.FIREBASE_APP_ID }} serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }} groups: testers file: android/app/build/outputs/apk/debug/app-debug.apk releaseNotes: | 버전: ${{ steps.version.outputs.VERSION_NAME }} (${{ steps.version.outputs.BUILD_NUMBER }}) 빌드 날짜: $(date +'%Y-%m-%d %H:%M:%S') 커밋: ${{ github.sha }} - name: Google Play 배포 if: github.event.inputs.buildType == 'release-aab' uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }} packageName: com.zellyy.finance releaseFiles: android/app/build/outputs/bundle/release/app-release.aab track: internal status: completed releaseName: ${{ steps.version.outputs.VERSION_NAME }} releaseNotes: | ko-KR: 버전 ${{ steps.version.outputs.VERSION_NAME }} 업데이트 - 버그 수정 및 성능 개선 - name: 빌드 결과물 저장 uses: actions/upload-artifact@v3 with: name: app-${{ steps.version.outputs.VERSION_NAME }}-${{ steps.version.outputs.BUILD_NUMBER }} path: | android/app/build/outputs/apk/debug/*.apk android/app/build/outputs/apk/release/*.apk android/app/build/outputs/bundle/release/*.aab - name: 슬랙 알림 uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} fields: repo,message,commit,author,action,eventName,ref,workflow,job,took env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} if: always() ``` ### GitHub Secrets 설정 GitHub 저장소의 Settings > Secrets and variables > Actions에서 다음 시크릿을 설정해야 합니다: - `FIREBASE_APP_ID`: Firebase 프로젝트의 앱 ID - `FIREBASE_SERVICE_ACCOUNT`: Firebase 서비스 계정 JSON 파일 내용 - `PLAY_STORE_SERVICE_ACCOUNT_JSON`: Google Play 서비스 계정 JSON 파일 내용 - `SLACK_WEBHOOK_URL`: 슬랙 알림을 위한 웹훅 URL ## 버전 관리 자동화 ### 버전 관리 스크립트 `scripts/version-manager.sh` 파일을 생성하여 버전 관리를 자동화합니다. ```bash #!/bin/bash # version-manager.sh # 현재 버전 정보 가져오기 get_current_version() { if [ -f "android/app_version.json" ]; then VERSION_CODE=$(grep -o '"versionCode": [0-9]*' android/app_version.json | awk '{print $2}') VERSION_NAME=$(grep -o '"versionName": "[^"]*"' android/app_version.json | sed 's/"versionName": "//' | sed 's/"//') BUILD_NUMBER=$(grep -o '"buildNumber": [0-9]*' android/app_version.json | awk '{print $2}') # 값이 비어있는지 확인 if [ -z "$VERSION_CODE" ]; then VERSION_CODE=1; fi if [ -z "$VERSION_NAME" ]; then VERSION_NAME="1.0.0"; fi if [ -z "$BUILD_NUMBER" ]; then BUILD_NUMBER=1; fi else VERSION_CODE=1 VERSION_NAME="1.0.0" BUILD_NUMBER=1 fi echo "현재 버전 정보:" echo "버전 코드: $VERSION_CODE" echo "버전 이름: $VERSION_NAME" echo "빌드 넘버: $BUILD_NUMBER" } # 버전 정보 업데이트 update_version_files() { # version.properties 파일 업데이트 echo "buildNumber=$BUILD_NUMBER" > android/version.properties echo "versionCode=$VERSION_CODE" >> android/version.properties echo "versionName=$VERSION_NAME" >> android/version.properties # app 디렉토리에도 동일한 파일 복사 cp android/version.properties android/app/version.properties # app_version.json 파일 업데이트 cat > android/app_version.json << EOF { "versionCode": $VERSION_CODE, "versionName": "$VERSION_NAME", "buildNumber": $BUILD_NUMBER, "notes": "자동 업데이트된 버전 정보입니다." } EOF echo "버전 정보가 모든 파일에 저장되었습니다." } # 메인 함수 main() { get_current_version # 빌드 타입에 따라 버전 증가 case "$1" in "debug") BUILD_NUMBER=$((BUILD_NUMBER + 1)) ;; "release") VERSION_CODE=$((VERSION_CODE + 1)) BUILD_NUMBER=$VERSION_CODE ;; *) echo "사용법: $0 [debug|release]" exit 1 ;; esac update_version_files echo "업데이트된 버전 정보:" echo "버전 코드: $VERSION_CODE" echo "버전 이름: $VERSION_NAME" echo "빌드 넘버: $BUILD_NUMBER" } main "$@" ``` ### 버전 관리 규칙 Zellyy Finance 앱의 버전 관리는 다음 규칙을 따릅니다: - **versionCode**: 앱스토어에 제출할 때마다 증가하는 정수 값 - **versionName**: 사용자에게 표시되는 버전 (예: "1.0.0") - **buildNumber**: 내부 빌드 추적을 위한 번호 ## 테스트 빌드 배포 및 설치 테스트 빌드가 완료된 후 개발자와 테스터가 앱을 설치하고 테스트할 수 있는 방법을 설명합니다. ### Firebase App Distribution을 통한 배포 Firebase App Distribution은 테스트 버전 앱을 테스터에게 쉽게 배포할 수 있는 서비스입니다. #### 설정 방법 1. **Firebase 프로젝트 설정**: - [Firebase 콘솔](https://console.firebase.google.com/)에서 프로젝트 생성 - App Distribution 서비스 활성화 - 테스터 그룹 생성 및 테스터 이메일 추가 2. **GitHub Actions 설정**: - `FIREBASE_APP_ID`와 `FIREBASE_SERVICE_ACCOUNT` 시크릿 설정 - 워크플로우 파일에 Firebase 배포 단계 추가 #### 테스터 초대 및 앱 설치 방법 ##### 안드로이드 테스터 1. **테스터 초대**: - Firebase 콘솔에서 테스터 이메일 추가 - 테스터에게 초대 이메일 발송 2. **앱 설치 방법**: - 테스터는 초대 이메일의 링크를 클릭 - Firebase App Tester 앱 설치 (처음 사용 시) - 테스트 앱 다운로드 및 설치 - 설치 시 "알 수 없는 출처" 앱 설치 허용 필요 ```bash # 안드로이드 테스터를 위한 안내 메시지 예시 안드로이드 테스트 앱 설치 방법: 1. 초대 이메일의 링크를 클릭하세요 2. Firebase App Tester 앱을 설치하세요 (처음 사용 시) 3. 테스트 앱을 다운로드하고 설치하세요 4. 설정 > 보안 > 알 수 없는 출처에서 설치 허용을 활성화하세요 ``` ##### iOS 테스터 1. **TestFlight 설정**: - Apple Developer 계정에서 앱 등록 - 내부 테스터 그룹 생성 2. **테스터 초대**: - App Store Connect에서 테스터 이메일 추가 - 테스터에게 초대 이메일 발송 3. **앱 설치 방법**: - 테스터는 초대 이메일의 링크를 클릭 - TestFlight 앱 설치 (App Store에서 다운로드) - TestFlight를 통해 테스트 앱 설치 ```bash # iOS 테스터를 위한 안내 메시지 예시 iOS 테스트 앱 설치 방법: 1. 초대 이메일의 링크를 클릭하세요 2. App Store에서 TestFlight 앱을 설치하세요 3. TestFlight 앱을 열고 테스트 앱을 설치하세요 ``` ### GitHub Actions Artifacts를 통한 직접 다운로드 Firebase App Distribution 외에도 GitHub Actions의 Artifacts 기능을 사용하여 빌드 결과물을 직접 다운로드할 수 있습니다. 1. **빌드 결과물 확인**: - GitHub 저장소의 Actions 탭으로 이동 - 해당 워크플로우 실행 결과 페이지 열기 - Artifacts 섹션에서 APK 또는 IPA 파일 다운로드 2. **안드로이드 APK 설치**: - 다운로드한 APK 파일을 안드로이드 기기로 전송 - 파일 관리자에서 APK 파일 실행 - 알 수 없는 출처 앱 설치 허용 3. **iOS IPA 설치** (개발자만 가능): - Apple Developer 계정이 있는 개발자만 가능 - Xcode 또는 Apple Configurator를 사용하여 설치 ### QR 코드를 통한 간편 설치 테스터의 편의를 위해 QR 코드를 생성하여 배포할 수도 있습니다: ```yaml - name: QR 코드 생성 if: github.event.inputs.buildType == 'debug' run: | # Firebase 배포 URL에 대한 QR 코드 생성 FIREBASE_URL="https://appdistribution.firebase.dev/i/..." curl -s "https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=$FIREBASE_URL" > qrcode.png echo "QR 코드가 생성되었습니다. 테스터는 이 코드를 스캔하여 앱을 설치할 수 있습니다." - name: QR 코드 저장 if: github.event.inputs.buildType == 'debug' uses: actions/upload-artifact@v3 with: name: install-qrcode path: qrcode.png ``` ## 앱스토어 자동 배포 ### Google Play Store 배포 Google Play Store에 자동으로 앱을 배포하려면 다음 단계가 필요합니다: 1. **Google Play Console 설정**: - API 액세스 활성화 - 서비스 계정 생성 및 권한 부여 - JSON 키 다운로드 2. **GitHub Actions 설정**: - `PLAY_STORE_SERVICE_ACCOUNT_JSON` 시크릿 설정 - 워크플로우 파일에 배포 단계 추가 ### Apple App Store 배포 Apple App Store에 자동으로 앱을 배포하려면 Fastlane을 사용합니다: 1. **Fastlane 설정**: - iOS 디렉토리에 Fastfile 생성 ```ruby default_platform(:ios) platform :ios do desc "배포용 iOS 앱 빌드 및 TestFlight 업로드" lane :release do setup_ci # 인증서 및 프로비저닝 프로파일 동기화 match( type: "appstore", readonly: true ) # 버전 업데이트 increment_build_number( build_number: ENV["BUILD_NUMBER"] ) # 앱 빌드 build_app( scheme: "App", workspace: "App.xcworkspace", export_method: "app-store" ) # TestFlight 업로드 upload_to_testflight( skip_waiting_for_build_processing: true ) end end ``` 2. **GitHub Actions 설정**: - App Store Connect API 키 생성 및 GitHub Secrets에 저장 - 워크플로우 파일에 iOS 빌드 및 배포 단계 추가 ## 비용 분석 ### GitHub Actions 비용 GitHub Actions는 다음과 같은 무료 할당량을 제공합니다: - **퍼블릭 저장소**: 무제한 무료 사용 가능 - **프라이빗 저장소**: - GitHub Free: 매월 2,000분의 무료 빌드 시간 - GitHub Pro: 매월 3,000분의 무료 빌드 시간 - GitHub Team: 매월 계정당 3,000분의 무료 빌드 시간 - GitHub Enterprise: 매월 계정당 50,000분의 무료 빌드 시간 ### Zellyy Finance 앱의 예상 비용 - **빌드 시간 예상**: 한 번의 워크플로우당 약 7-20분 - **월간 빌드 횟수 시나리오**: - 하루 1회 빌드: 월 30회 × 15분 = 450분 - 하루 3회 빌드: 월 90회 × 15분 = 1,350분 - 하루 5회 빌드: 월 150회 × 15분 = 2,250분 - **비용 계산**: - GitHub Free 계정 사용 시: 월 2,000분 무료 (하루 4회 빌드까지 무료) - 초과 사용 시: 분당 $0.008 (Linux 머신 기준) ### 비용 최적화 전략 1. **캐싱 활용**: ```yaml - uses: actions/cache@v3 with: path: | ~/.npm node_modules android/.gradle key: ${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }} ``` 2. **빌드 트리거 최적화**: ```yaml on: push: branches: [ main, develop ] paths-ignore: - '**.md' - 'docs/**' ``` 3. **조건부 작업 설정**: ```yaml - name: Google Play 배포 if: github.ref == 'refs/heads/main' && github.event.inputs.buildType == 'release-aab' # ... ``` ## 문제 해결 및 FAQ ### 자주 발생하는 문제 1. **빌드 실패**: - 종속성 문제: `npm ci` 대신 `npm install`을 사용해 보세요. - 캐시 문제: 캐시를 삭제하고 다시 시도하세요. 2. **버전 관리 문제**: - 버전 파일이 비어 있는 경우: 스크립트가 기본값을 설정하도록 합니다. - 버전 코드 충돌: 수동으로 버전 코드를 설정하여 해결합니다. 3. **배포 실패**: - 인증 문제: 서비스 계정 권한을 확인하세요. - 앱 서명 문제: 키스토어 설정을 확인하세요. ### FAQ **Q: 워크플로우를 수동으로 실행하려면 어떻게 해야 하나요?** A: GitHub 저장소의 Actions 탭에서 "Zellyy Finance CI/CD" 워크플로우를 선택하고 "Run workflow" 버튼을 클릭합니다. **Q: 특정 커밋에서 빌드를 실행하려면 어떻게 해야 하나요?** A: 해당 커밋으로 체크아웃한 후 수동으로 워크플로우를 실행하거나, GitHub API를 사용하여 특정 커밋에서 워크플로우를 트리거할 수 있습니다. **Q: 빌드 결과물은 어디에서 찾을 수 있나요?** A: 워크플로우 실행 페이지의 "Artifacts" 섹션에서 다운로드할 수 있습니다. **Q: 테스터가 테스트 앱을 설치하는 가장 쉬운 방법은 무엇인가요?** A: Firebase App Distribution을 사용하는 것이 가장 쉽습니다. 테스터는 이메일로 초대를 받고 링크를 통해 앱을 설치할 수 있습니다. QR 코드를 제공하면 더욱 편리하게 설치할 수 있습니다. **Q: iOS 테스트 앱 설치 시 개발자 계정이 필요한가요?** A: TestFlight를 통한 배포의 경우 테스터는 개발자 계정이 필요하지 않습니다. 하지만 개발자는 Apple Developer 계정이 필요합니다. GitHub Actions Artifacts를 통한 직접 설치는 개발자만 가능합니다.