🙋‍♀️ Android

[Android] GitHub Actions 을 통한 CI/CD 구축

수댕ʕت̫͡ʔ 2024. 8. 20. 00:37

1. 문제 인식

앱 개발 프로젝트를 진행하면서 팀의 협업 방식이 비효율적이라고 느꼈다. 왜냐하면, 현재 다음과 같은 프로세르를 통하기 때문이다.

 

1) 각자 코드를 작성, 수정한다.

2) 작성한 코드를 각자 테스트, 빌드한다.

3) 팀원들과 모여서 합친다.

 

이 과정은 모든 팀원이 합치면 8번의 반복적인 과정을 거치게 된다..! 이는 매우 비효율적이다.

이를 개선하기 위해 나는 CI/CD 파이프라인을 작성하기로 결정했다.

 

2. CI/CD 파이프라인 구성

GitHub Actions 을 사용하여 CI/CD 파이프라인을 설정했다.

주요 과정은 다음과 같다.

 

1) 브랜치에 Push

- 각 브랜치에 코드를 push할 때 마다 자동으로 CI/CD 파이프라인이 실행된다.

 

2) 테스트

- 코드를 Push하면 먼저 자동으로 테스트가 실행된다. 이를 통해 코드의 품질과 안정성을 검증한다.

 

3) 빌드

- 테스트가 완료되면, 코드를 빌드하여 앱을 생성한다.

 

4) APK, AAB 파일 생성

- 빌드가 완료되면 APK, AAB 파일이 배포된다.

 

 

3. 고민했던 것

내가 여기서 고민했던 것이 있다!

 

1. 자동 병합의 유용성 고민

자동으로 테스트가 완료된 브랜치를 main 브랜치에 병합하는 방식에 대해 고민했다. 하지만 다음과 같은 이유로 이 방식은 우리 팀에 적합하지 않다고 판단했다.

 

- 코드 검토 및 결정 : 우리는 각자 작업한 후, 완성물을 확인하고 최종 결정을 내린 후 병합한다. 그렇기 때문에 자동으로 병합하는 것은 코드 수정이 복잡해질 수 있는 위험이 있다.

 

따라서, 코드 병합 전에 팀원들과 직접 검토하고 논의하는 과정이 필수적이다!

 

따라서 이것은 PASS 했다.

 

2. 자동 앱 업데이트의 필요성

나는 현재는 APK, AAB 파일만 자동 배포되는 형식으로 파이프라인을 작성했다. 

사실 AAB 파일을 자동으로 Google Play Store에 업데이트하는 방식도 고려했다. 하지만 다음과 같은 이유로 이 방식도 우리 팀에 적합하지 않다고 판단했다.

 

- 검증 과정 : 메인 브랜치에 병합한 후, 실제 다양한 기종의 핸드폰에서 잘 작동되는지 확인하는 과정이 필요하다. 따라서 자동 업데이트는 오류가 발생할 확률이 높을 수 있다.

 

따라서, 앱의 안정성을 유지하기 위해서는 수동으로 검토 후 업데이트하는 것이 적절하다!

 

따라서 이것도 PASS 했다.

 

4. 최종 결정

결국, 다음과 같은 파이프라인을 구성하여 효율성을 높였다.

 

각 브랜치에 코드를 push -> test -> build -> APK/AAB 파일 배포

 

5. 코드

여기서 코드를 살펴보자.

on:
  push:
    branches: 
      - '**'
  pull_request:
    branches: 
      - 'main'

 

 

모든 브랜치에 푸시가 발생하면 워크플로우가 실행된다. 그리고 main 브랜치에 Pull Request가 생성될 때 워크플로우가 실행된다.

 

 steps:
    - uses: actions/checkout@v4 # 소스 코드 깃허브에 checkout
    - name: set up JDK 18
      uses: actions/setup-java@v4
      with:
        java-version: '18' # JDK 18을 설치하고 설정
        distribution: 'temurin'
        cache: gradle

    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      
    - name: Clean Bulid
      run: ./gradlew clean # Gradle 빌드 클린
      
    - name: Run lint
      run: ./gradlew lintDebug -Dlint.baselines.continue=true # 코드 린트 실행해서 코드 품질 검사

    - name: Build with Gradle
      # 프로젝트 빌드하고 에러 발생하면 스택 트레이스 출력
      run: ./gradlew build --stacktrace

 

 

코드를 빌드 테스트한다. 빌드 중에 에러가 발생하면 어떤 에러인지 출력해서 확인할 수 있게 했다.

 

 # 참고! 빌드 성공하면 자동으로 apk 생성하도록 함
    - name: Build APK
      run: ./gradlew assembleRelease
      
    - name: Build AAB
      run: ./gradlew bundleRelease # AAB 파일 생성

    - name: Upload APK and AAB
      uses: actions/upload-artifact@v3
      with:
        name: artifacts
        path: |
          app/build/outputs/apk/release/app-release.apk # APK 파일 경로
          app/build/outputs/bundle/release/app-release.aab # AAB 파일 경로

 

그 다음 APK, AAB 파일을 생성하게 한다. 구글플레이스토어에 앱을 업데이트하려면 AAB 파일이 필요하기 때문이다.

 

 

참고로!! 

각 브랜치에서 빌드가 성공하면 main으로 자동 병합되는 코드를 다음과 같다. 

근데 혹시 테스트를 추천한다! 왜냐면 우리팀에는 사용 안해봤기때문!!ㅎㅎ

    # # 참고! 각 브랜치에서 빌드 성공하면 main으로 자동 병합
    # - name : Auto-merge to main
    #   if: github.ref != 'refs/heads/main' && success()
    #   run: |
    #     git config --global user.email "github-actions@github.com"
    #     git config --global user.name "GitHub Actions"
    #     git fetch origin
    #     git checkout ${GITHUB_REF}
    #     git merge origin/main --no-ff -m "${GITHUB_REF} branch BeyourEyes Merge success"
    #     git push origin ${GITHUB_REF}
    #     env:
    #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

 

 

나는 CI/CD를 구축하면서, 자동화의 필요와 수동의 필요성을 돌아보는 시간을 가졌다. 

정말 어떤 방법이 효율적인지 판단하는 것은 팀마다 다르다!

우리처럼 수동으로 테스트를 해봐야하는 부분이 필수적이면, CD를 구성하는 것은 다소 제한적이다.

그래서 나는 적당히 APK, AAB 파일을 생성하는것으로 CD를 구축한 것이다.

 

CI/CD는 협업을 효율적으로 하지만, 어떻게 작성할 것인지는 팀과 논의 후 판단하는 것이 적절하다.