Skip to content

학습‐android CI 적용기

easyhak edited this page Nov 22, 2024 · 2 revisions

저희 프로젝트는 협업할 때 main branch로 merge 되기 전에 자동으로 test, lint check, build 되는지 확인하도록 했습니다.

github actions을 통해 ktlint, debug.keystore, google-services.json을 관리하며 CI(Continuous Integration) 구축을 한 방법에 대해 작성해보겠습니다.

CI 환경 설정

Github Actions 사용

저희는 github를 이용하여 개발을 진행했기에 쉽게 사용할 수 있는 github actions를 사용하였습니다. dev, main branch로 병합되기 전에 build, ktlint가 성공해야지 병합될 수 있도록 했습니다

build.yml 파일을 작성하여 pull_request 이벤트가 발생하면 빌드 작업이 실행되도록 했습니다.

name: Build

on:
  pull_request:
    branches: [ "main", "dev" ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Gradle Caching
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Run Build
        run: ./gradlew build --no-daemon

ktlint 관리

팀원들끼리 같은 코틀린 스타일 규칙을 적용하는 것이 필요했습니다. 참고: lint적용

그래서 저희는 ktlint를 도입하여 팀원들이 작성한 코드가 일관된 컨벤션 규칙을 따르도록 강제했습니다. ktlint_check.yml 파일을 작성해 pull_request 이벤트 발생시 workflow이벤트가 실행되도록 했습니다.

name: ktlint chcek

on:
  pull_request:
    branches: [ "main", "dev" ]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Gradle Caching
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Run ktlintCheck
        run: ./gradlew ktlintCheck --no-daemon

저희는 이 두개의 workflow를 통과해야지만 merge 될 수 있도록 했습니다.

로그인 구현할 때의 문제점

저희는 firebase를 사용하여 로그인을 구현하면서 google-services.json*.keystore를 읽어오는 작업이 필요했습니다. 하지만 이 두개는 공개된 github repository에 올리면 안됬습니다.

이를 해결하기위해 setting > security > secrets and variables > actions에서 secret 값을 추가해줬습니다. 그리고 debug.keystore는 올릴 수 없었기에 Window powershell에서 base64로 인코딩 해줬습니다.

[Convert]::ToBase64String((Get-Content -Path .\debug.keystore -Encoding Byte)) > debug.keystore.base64

image

그리고 app모듈의 build.gradle.kts에서 keystore를 읽는 부분을 수정하였습니다.

getByName("debug") {
    val keystoreProperties = Properties().apply {
        val file = rootProject.file("local.properties")
        if (file.exists()) {
            load(file.inputStream())
        }
    }
    val keyStorePath = keystoreProperties.getProperty("DEBUG_KEYSTORE_PATH")
    storeFile = if (keyStorePath != null) {
        file(keyStorePath)
    } else {
        file("${System.getProperty("user.home")}/.android/debug.keystore")
    }
}

또한 debug.keystore를 읽을 수 있도록 workflow도 수정해줬습니다.

최종 코드

ktlint_check.yml

name: ktlint chcek

on:
  pull_request:
    branches: [ "main", "dev" ]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Gradle Caching
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Decode Google Services JSON
        env:
          GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo "$GOOGLE_SERVICES_JSON" > ./app/google-services.json

      - name: Run ktlintCheck
        run: ./gradlew ktlintCheck --no-daemon

build.yml

name: Build

on:
  pull_request:
    branches: [ "main", "dev" ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Gradle Caching
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Decode Google Services JSON
        env:
          GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
        run: echo "$GOOGLE_SERVICES_JSON" > ./app/google-services.json

      - name: Decode Debug Keystore
        env:
          DEBUG_KEYSTORE_BASE64: ${{ secrets.DEBUG_KEYSTORE_BASE64 }}
        run: |
          mkdir -p $HOME/.android
          echo "$DEBUG_KEYSTORE_BASE64" | base64 -d > $HOME/.android/debug.keystore

      - name: Run Build
        run: ./gradlew build --no-daemon

위와 같이 작성하니 CI 작업이 잘 실행되었습니다!!!

Clone this wiki locally