π‘λΉλμ ν μ€νΈ, λ°°ν¬μ νμ©λλ CI/CDμ λνμ¬ νμ΅ ν μ 리νμμ΅λλ€.
CI/CD?
- CI/CDλ μννΈμ¨μ΄ κ°λ° νλ‘μΈμ€λ₯Ό μλννκ³ ν¨μ¨μ μΌλ‘ λ§λ€κΈ° μν κ°λ° κ΄νμ λλ€.
- μ½λλ₯Ό μμ λ¨μλ‘ μμ£Ό λ³ν©νκ³ , μλνλ ν μ€νΈμ λ°°ν¬λ₯Ό ν΅ν΄ μμ μ μ΄κ³ μ μν μννΈμ¨μ΄ 릴리μ€λ₯Ό κ°λ₯νκ² νλ λͺ©νλ₯Ό κ°μ§κ³ μμ΅λλ€.
CI (Continuous Integration)
- κ°λ°μλ€μ΄ μμ£Ό μ½λλ₯Ό ν΅ν©νκ³ λ³κ²½ μ¬νμ λ²μ κ΄λ¦¬ μμ€ν μ λ³ν©νλ κ³Όμ μ λλ€.
- CI νμ΄νλΌμΈμ μ½λ λ³κ²½ μ¬νμ΄ λ³ν©λ λλ§λ€ μλμΌλ‘ λΉλ, ν μ€νΈλ₯Ό μ€ννμ¬ μ½λ νμ§μ 보μ₯ν©λλ€.
CD (Continuous Delivery/Deployment)
- Continuous Deliveryλ CI μ΄ν, κ²μ¦λ μ½λκ° μλμΌλ‘ μ€λΉλ νλ‘λμ
λ°°ν¬ λ²μ ΌμΌλ‘ 릴리μ€λ μ μκ² νλ κ³Όμ μ
λλ€.
- μ΅μ’ λ°°ν¬λ μλμΌλ‘ μ΄λ£¨μ΄μ§ μ μμ΅λλ€.
- Continuous Deploymentλ Continuous Deliveryλ³΄λ€ ν λ¨κ³ λ λμκ°μ, ν μ€νΈλ₯Ό ν΅κ³Όν μ½λλ₯Ό μλμΌλ‘ νλ‘λμ νκ²½μ λ°°ν¬νλ κ³Όμ μ λλ€.
κ΅¬μΆ λꡬ
- CI/CD νμ΄νλΌμΈμ ꡬμΆνλ λκ΅¬λ‘ Jenkins, GitHub Actions, Bitrise, CircleCI, GitLab CI λ±μ΄ νμ©λ©λλ€.
- μ΄λ¬ν λꡬλ€μ μ½λκ° μ»€λ°λ λλ§λ€ λΉλνκ³ ν μ€νΈλ₯Ό μ€ννλ©°, μ±κ³΅μ μΈ λΉλ νμ λ°°ν¬λ₯Ό μ§νν©λλ€.
νμ΄νλΌμΈ
CI/CD νμ΄νλΌμΈ ꡬμΆμ μλλ‘μ΄λ μ± κ°λ° νκ²½μ μ€μ¬μΌλ‘ μμ±νμμΌλ©° λΉλ, ν μ€νΈ, λ°°ν¬ νλ‘μΈμ€λ₯Ό μλννλ κ²μ λͺ©νλ‘ νμμ΅λλ€.
μ½λ νΈμ νΈλ¦¬κ±°
- κ°λ°μκ° Git μ μ₯μμ μ½λ νΈμ λλ PRμ μμ±ν λλ§λ€ νμ΄νλΌμΈμ΄ μλμΌλ‘ μμλ©λλ€.
λΉλ μλν
- Gradleμ νμ©ν΄ μλλ‘μ΄λ νλ‘μ νΈλ₯Ό λΉλν©λλ€.
- assembleDebug or asReleaseμ κ°μ Gradle λͺ λ Ήμ΄λ₯Ό μ¬μ©νμ¬ APK, AAB νμΌμ μμ±ν μ μμ΅λλ€.
./gradlew assembleDebug
ν μ€νΈ μλν
- μ λ ν μ€νΈμ UI ν μ€νΈλ₯Ό μλμΌλ‘ μ€νν μ μμ΅λλ€.
- Robolectricμ μ¬μ©ν μ λ ν μ€νΈ λλ Espressoλ₯Ό μ¬μ©ν UI ν μ€νΈκ° ν¬ν¨λ©λλ€.
./gradlew testDebugUnitTest
./gradlew connectedAndroidTest
ν μ€νΈ 컀λ²λ¦¬μ§ λ° μ½λ νμ§ κ²μ¬
- μ½λ 컀λ²λ¦¬μ§ λκ΅¬λ‘ JaCoCoμ κ°μ λꡬλ₯Ό μ¬μ©νμ¬ μ½λ 컀λ²λ¦¬μ§λ₯Ό μΈ‘μ ν©λλ€.
- μ½λ νμ§ κ²μ¬ λκ΅¬λ‘ Lint, Detekt, Ktlintλ₯Ό μ¬μ©ν μ μμ΅λλ€.
./gradlew lint
./gradlew detekt
APK/AAB λ°°ν¬
- Firebase App Distribution, Google Play Console, TestFairy κ°μ νλ«νΌμ μ¬μ©ν΄ μ±μ ν μ€ν°μκ² λ°°ν¬ν μ μμ΅λλ€.
- μ΄ λ¨κ³λ λΉλκ° μ±κ³΅μ μΌλ‘ μλ£λ νμ μλμΌλ‘ μ€νλκ² ν μ μμ΅λλ€.
./gradlew publishReleaseApk
CI/CD ꡬμΆ
μλλ‘μ΄λμμ CI/CD ꡬμΆμ ν΅ν΄ κ°λ°μ μ½λ νμ§ μ μ§μ ν μ€νΈ μλνλ‘ μ½κ² μ±μ λ°°ν¬ν μ μμ΅λλ€. μλνλ CI/CD νμ΄νλΌμΈμ ν΅ν΄ κ°λ°κ³Ό λ°°ν¬ μλλ₯Ό λμ΄κ³ μ λ’°μ±μ ν보ν μ μμ΅λλ€.
ON
- onμ μ΄λ²€νΈ λ°μμ λν CI/CD μ€νμ μ§μ ν μ μμ΅λλ€.
- master λΈλμΉμ push λλ PR μ΄λ²€νΈκ° λ°μνλ©΄ CI/CDλ₯Ό μ€ννλλ‘ μ§μ ν©λλ€.
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
Jobs
- Jobsλ μ€νν μμ λ€μ λμ΄ν©λλ€.
jobs:
build:
runs-on
- runs-onμ λΉλ μμ μ΄ μ€νλ νκ²½μ μ μν©λλ€.
- μ΅μ λ²μ μ Ubuntu νκ²½(Default)λ₯Ό μ§μ νμμ΅λλ€.
runs-on: ubuntu-latest
steps
- stepsμλ μμ μ΄ μ€νλ μμλ₯Ό μ μν μ μμ΅λλ€.
- μ€ννκ³ μΆμ μμ μ λμ΄νλ©°, Jobs λΈλ μμ μ μΈν΄μΌ ν©λλ€.
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: '11'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle
- name: Build with Gradle
run: ./gradlew build
- name: Run unit tests
run: ./gradlew testDebugUnitTest
- name: Run Android Lint
run: ./gradlew lint
- name: Assemble Debug APK
run: ./gradlew assembleDebug
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: app-debug.apk
path: app/build/outputs/apk/debug/app-debug.apk