Github Action으로 CI환경 구축하기
오늘은 Github Action을 이용하여 CI환경을 구축하고, CI를 통해 build, lint, testcode 등 다양한 검증을 자동화하는 방법에 대해 이야기해보려 합니다!
CI란 뭘까?
CI(지속적인 통합)는 변경사항을 배포 시 한꺼번에 통합하는 것이 아닌, 자주, 지속적으로 통합하는 것을 의미합니다. 협업이 필수인 시대가 되면서, 개발자들은 각각 작업할 파트를 나누어 하나의 제품을 만듭니다. 그러나 CI 환경이 구축되지 않았다면, 배포 단계 막바지에 테스트를 수행하게 되면서 여러 가지 이슈와 사이드 이펙트를 한꺼번에 감당해야 합니다.
이러한 문제를 해결하기 위해 등장한 기법이 CI (지속적인 통합)입니다. CI 환경을 구축하여 빌드, 린트, 테스트 검증 등을 통해 지속적으로 코드의 품질 관리 및 기능 검증을 수행하게 됩니다. 이를 개발 과정에서 발생할 수 있는 이슈를 조기에 발견하고 수정할 수 있게 하며, 최종적으로는 제품의 안정성과 품질을 높이는 효과를 볼 수 있습니다.
CI 도구로는 Jenkins, Travis CI, CircleCI, GitLab CI/CD 등 여러 가지 도구가 있지만, 오늘은 Github Action을 이용하여 간단하게 CI환경을 구축하는 방법에 대해 설명하고자 합니다.
Github Action을 이용해 Android CI환경 구축하기
1. workflow 이름 및 작동 조건 설정
name: Android CI
run-name: Android CI
on:
pull_request:
branches:
- main
workflow파일의 이름과 작업의 이름을 설정해 줍니다. 이후 작동 조건을 설정해 줍니다. 제가 작성한 예제의 경우에는 main브랜치에 PR이 올라왔을 때 workflow가 동작하도록 세팅되어 있습니다.
PR 이외에도 다양한 조건을 세팅할 수 있습니다. 자세한 내용은 Github Action 공식문서를 참고하시면 좋을 것 같습니다.
2. 빌드 환경 세팅
jobs:
build:
runs-on: ubuntu-latest
다음으론 빌드 환경을 세팅해 줍니다. 예제코드의 경우에는 우분투 환경에서 빌드되도록 작업되어 있습니다.
3. 레포지토리에 접근할 수 있게 checkout 진행
- uses: actions/checkout@v3
레포지토리에 접근하여 빌드를 진행할 수 있도록 checkout을 진행해 주었습니다.
4. JDK, SDK세팅
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Set up Android SDK
uses: android-actions/setup-android@v2
빌드를 위해 JDK, SDK를 세팅해 주었습니다.
5. gradlew 실행 권한 부여
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
workflow파일이 gradlew명령어를 실행할 수 있도록 권한을 부여해 줍니다.
6. 시크릿 파일들 준비
- name: Prepare Environment
run: |
echo '${{ secrets.GOOGLE_SERVICES }}' > app/google-services.json;
echo "org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8" >> gradle.properties
- name: Decode keystore
run: |
echo "$KEYSTORE" > fanwoori.b64
base64 -d -i fanwoori.b64 > fanwoori.jks
env:
KEYSTORE: ${{ secrets.ENCODED_KEYSTORE }}
빌드에 필요한 시크릿 파일들을 준비해 줍니다. 먼저 저희 프로젝트에서 사용하는 firebase 관련 google-services.json 파일을 생성해 줍니다.
그다음 암호화되어 있는 키스토어 파일을 가져와 복호화하여 jks 파일로 생성합니다.
7. 빌드 및 Lint체크
- name: Build & Ktlint Check
run: ./gradlew ktlintCheck build
모든 준비 과정이 끝났으면 코드를 검증할 차례입니다. 빌드와 lint 검증을 한 번에 하기 위해./gradlew ktlintCheck build를 사용하였습니다.
8. Unit테스트 실행 및 리포트 생성
- name: Run TestCode
run: ./gradlew testDebugUnitTest
- name: Reporting TestCode Result
uses: EnricoMi/publish-unit-test-result-action@v1
if: ${{ always() }}
with:
files: '**/build/test-results/testDebugUnitTest/*.xml'
빌드 검증이 끝났으면 테스트 코드를 실행할 차례입니다. 먼저 명령어를 이용하여 테스트 코드를 실행해 주고 그 결과를 PR comment로 달아줍니다. PR comment를 달 때는 EnricoMi의 publish-unit-test-result-action@v1을 사용하였습니다.
추가로 if문 안에 always로 조건이 걸려있는 이유는, 위 작업인 테스트 코드가 실패하던 성공하던 어느 경우에서든 PR에 comment를 남기게 하기 위함입니다.
9. 코드 커버리지 체크 및 리포트 등록
- name: Check Code Coverage
run: ./gradlew jacocoTestReport
- name: Reporting Code Coverage Result
id: jacoco
uses: madrapps/jacoco-report@v1.2
with:
paths: ${{ github.workspace }}/domain/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
token: ${{ secrets.GITHUB_TOKEN }}
min-coverage-overall: 60
min-coverage-changed-files: 60
제 프로젝트에는 코드 커버리지를 확인하기 위해 jacoco가 설정되어 있습니다. CI 작업에서도 이를 한 번씩 확인해 리포트로 받아보면 좋을 것 같아 추가하였습니다. Jacoco 리포트 확인에는 madrapps의 jacoco-report@v1.2를 사용하였습니다.
Gradle Caching 추가
저희 프로젝트에는 난독화 코드가 적용되어 있어 gradle 빌드에 많은 시간이 소요되고 있었습니다, 이를 해결하고자 CI실행 시 Gradle캐싱을 통해 빌드 시간 단축을 시도하였습니다.
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
적용 전 평균 23분씩 걸리던 작업이 17분으로 단축된 걸 확인할 수 있었습니다.
마무리
오늘은 Github Action을 통해 간단하게 CI환경을 구축하는 방법에 대해 알아보았습니다. 실제로 CI환경을 구축해 보니, 이것만으로도 프로젝트의 안정성이 많이 향상된 걸 느낄 수 있었습니다. 현재 팀이나 프로젝트의 상황을 충분히 고려해서 도입했을 때 가치가 있다고 판단된다면 한 번쯤 도입해 보시는 것도 좋을 것 같습니다.
오늘도 글 읽어주셔서 감사합니다, 글에 대한 피드백은 언제나 환영입니다!
'ETC' 카테고리의 다른 글
[ETC] Github Action을 이용해 Android CD환경 구축하기 (0) | 2024.07.04 |
---|---|
[Android/ETC] android studio resource manager로 리소스 간편하게 관리하기! (0) | 2024.03.24 |