Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c8914f2
core: firebase 의존성 추가
changs97 Aug 11, 2025
d2402f5
Merge remote-tracking branch 'origin/master' into develop
changs97 Aug 11, 2025
7527c4c
feat: ci/cd 스크립트 수정
changs97 Aug 11, 2025
6904ab9
fix: 파이어베이스 의존성 수정
changs97 Aug 11, 2025
bca4b61
fix: firebase.crashlytics 다운그레이드
changs97 Aug 11, 2025
6541755
fix: ci/cd update
changs97 Aug 11, 2025
7a16048
fix: ci/cd update
changs97 Aug 11, 2025
dd85d80
fix: 빌드 경고 수정
changs97 Aug 11, 2025
f81fbd1
fix: ci/cd update
changs97 Aug 11, 2025
f094100
fix: get baseurl
changs97 Aug 11, 2025
9f664cc
fix: get baseurl
changs97 Aug 11, 2025
1160106
fix: get baseurl
changs97 Aug 11, 2025
a7f4b62
fix: ci/cd update
changs97 Aug 11, 2025
51e67b9
fix: ci/cd update
changs97 Aug 11, 2025
a9d3874
fix: getBaseUrl
changs97 Aug 11, 2025
44925a5
fix: ci/cd update
changs97 Aug 11, 2025
b9a120c
fix: ci/cd update
changs97 Aug 11, 2025
4685289
fix: test 의존성 누락 추가
changs97 Aug 11, 2025
166caf7
fix: test 의존성 누락 추가
changs97 Aug 11, 2025
1d8d1ac
fix: ci/cd
changs97 Aug 11, 2025
6f6edcb
fix: ci/cd
changs97 Aug 12, 2025
d370b3e
fix: 공지 타입일 경우 기간이 아닌 등록 날짜 표시하도록 수정
changs97 Aug 12, 2025
b1a8a9a
fix: ci/cd 슬랙 apk 업로드
changs97 Aug 12, 2025
0e9590a
fix: ci/cd 슬랙 apk 업로드
changs97 Aug 12, 2025
5df070e
fix: ci/cd 슬랙 apk 업로드 제거
changs97 Aug 12, 2025
0592b00
feat: Firebase 이벤트 로그 추가
changs97 Aug 12, 2025
9cbadb1
feat: ci/cd 개선
changs97 Aug 15, 2025
c38501e
feat: ci/cd 개선
changs97 Aug 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 152 additions & 44 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,89 @@
name: Android CI

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

# 전체 워크플로우에 대한 권한 설정
permissions:
contents: write

# 워크플로우 최적화
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:

runs-on: ubuntu-latest

# 빌드 캐시 설정
env:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError

steps:
- uses: actions/checkout@v4
- name: set up JDK 11

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

- name: Setup Gradle Cache
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: Setup Android SDK Cache
uses: actions/cache@v4
with:
path: |
~/.android/build-cache
~/.android/cache
key: ${{ runner.os }}-android-${{ hashFiles('**/gradle.properties', '**/local.properties') }}
restore-keys: |
${{ runner.os }}-android-

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

- name: Set Gradle Memory Settings
run: |
cat > gradle.properties << 'EOF'
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
EOF
echo "Gradle properties file created with memory settings:"
cat gradle.properties

- name: Add Local Properties
env:
BASE_URL: ${{secrets.BASE_URL}}
Expand All @@ -32,30 +93,49 @@ jobs:
SIGNING_KEY_ALIAS: ${{secrets.SIGNING_KEY_ALIAS}}
SIGNING_KEY_PASSWORD: ${{secrets.SIGNING_KEY_PASSWORD}}
run: |
echo "BASE_URL=$BASE_URL" >> ./local.properties
echo "GOOGLE_API_KEY=$GOOGLE_API_KEY" >> ./local.properties
echo "KAKAO_API_KEY=$KAKAO_API_KEY" >> ./local.properties
echo "SIGNING_STORE_PASSWORD=$SIGNING_STORE_PASSWORD" >> ./local.properties
echo "SIGNING_KEY_ALIAS=$SIGNING_KEY_ALIAS" >> ./local.properties
echo "SIGNING_KEY_PASSWORD=$SIGNING_KEY_PASSWORD" >> ./local.properties
echo "DEBUG: BASE_URL from secrets = '$BASE_URL'"
cat > local.properties << EOF
BASE_URL=$BASE_URL
GOOGLE_API_KEY=$GOOGLE_API_KEY
KAKAO_API_KEY=$KAKAO_API_KEY
SIGNING_STORE_PASSWORD=$SIGNING_STORE_PASSWORD
SIGNING_KEY_ALIAS=$SIGNING_KEY_ALIAS
SIGNING_KEY_PASSWORD=$SIGNING_KEY_PASSWORD
EOF
echo "Created local.properties at project root:"
ls -la local.properties
cat local.properties

- name: Get Google Services JSON
env:
GOOGLE_SERVICES_JSON: ${{secrets.GOOGLE_SERVICES_JSON}}
run:
echo '$GOOGLE_SERVICES_JSON' > ./app/google-services.json
run: |
echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json
echo "Google Services JSON file created successfully"
ls -la ./app/google-services.json

- name: Create Keystore File
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
run: |
echo $KEYSTORE_BASE64 | base64 -d > ./app/runcombi-keystore.jks

- name: Build with Gradle
run: ./gradlew build

- name: Build Release APK
run: ./gradlew assembleRelease
- name: Check if runcombi-keystore.jks exists
run: |
if [ -f "./app/runcombi-keystore.jks" ]; then
echo "✅ runcombi-keystore.jks file exists in the app directory."
ls -la ./app/runcombi-keystore.jks
else
echo "❌ Error: runcombi-keystore.jks file is missing in the app directory." >&2
exit 1
fi

- name: List keys in runcombi-keystore.jks
env:
SIGNING_STORE_PASSWORD: ${{secrets.SIGNING_STORE_PASSWORD}}
run: |
echo "Checking keystore contents..."
keytool -list -v -keystore ./app/runcombi-keystore.jks -storepass "$SIGNING_STORE_PASSWORD" || echo "Failed to list keystore contents"

- name: Extract App Version
id: app_version
Expand All @@ -64,12 +144,46 @@ jobs:
VERSION_CODE=$(grep 'versionCode' app/build.gradle.kts | sed 's/.*versionCode = \([0-9]*\)/\1/')
echo "version_name=$VERSION_NAME" >> $GITHUB_OUTPUT
echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION_NAME ($VERSION_CODE)"



- name: Build with Gradle
run: ./gradlew build --parallel --max-workers=2 --daemon

- name: Build Release APK
run: |
echo "Starting assembleRelease..."
./gradlew assembleRelease --parallel --max-workers=2 --daemon --info --stacktrace
echo "assembleRelease completed with exit code: $?"
echo "Checking if APK was generated..."
if [ -f "app/build/outputs/apk/release/app-release.apk" ]; then
echo "✅ APK file found!"
ls -la app/build/outputs/apk/release/
else
echo "❌ APK file not found!"
echo "Checking build directory..."
ls -la app/build/outputs/ || echo "Outputs directory not found"
echo "Checking for any APK files..."
find app/build/outputs/ -name "*.apk" -type f || echo "No APK files found"
fi

- name: Check APK output
run: |
echo "Checking APK output directory..."
ls -la app/build/outputs/apk/release/ || echo "Release directory not found"
echo "Checking all APK outputs..."
find app/build/outputs/ -name "*.apk" -type f || echo "No APK files found"
echo "Checking build directory structure..."
ls -la app/build/outputs/ || echo "Outputs directory not found"

- name: Upload Release Build to Artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts
path: app/build/outputs/apk/release/
path: |
app/build/outputs/apk/mock/release/
app/build/outputs/apk/prod/release/
if-no-files-found: error

- name: Create Github Release
Expand All @@ -79,7 +193,8 @@ jobs:
release_name: RunCombi Android v${{ steps.app_version.outputs.version_name }}
generate_release_notes: true
files: |
app/build/outputs/apk/release/app-release.apk
app/build/outputs/apk/mock/release/app-mock-release.apk
app/build/outputs/apk/prod/release/app-prod-release.apk
body: |
## RunCombi Android v${{ steps.app_version.outputs.version_name }}

Expand All @@ -90,49 +205,42 @@ jobs:
- PR: ${{ github.event.pull_request.title }}
- Author: @${{ github.event.pull_request.user.login }}
- Branch: ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}

### APK Files
- **Mock Release**: app-mock-release.apk
- **Prod Release**: app-prod-release.apk

- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{secrets.FIREBASE_APP_ID}}
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
groups: testers
file: app/build/outputs/apk/release/app-release.apk
file: app/build/outputs/apk/prod/release/app-prod-release.apk
releaseNotes: |
RunCombi Android v${{ steps.app_version.outputs.version_name }}

PR: ${{ github.event.pull_request.title }}
Author: @${{ github.event.pull_request.user.login }}
Branch: ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}

- name: Upload APK to Slack
if: ${{success()}}
uses: 8398a7/action-slack@v3
with:
status: success
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#general'
text: 'RunCombi Android APK 빌드 완료! 🎉'
file: app/build/outputs/apk/release/app-release.apk

APK: Prod Release Version

- name: If Success, Send notification on Slack
if: ${{success()}}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_COLOR: '#60E0C5'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_TITLE: 'RunCombi Android PR Check Success ✅'
SLACK_TITLE: 'RunCombi Android 빌드 성공 ✅'
MSG_MINIMAL: true
SLACK_USERNAME: RunCombi Android
SLACK_MESSAGE: 'RunCombi Android PR 체크 성공 🎉 (v${{ steps.app_version.outputs.version_name }} - ${{ steps.app_version.outputs.version_code }})%0A%0A**PR 제목:** ${{ github.event.pull_request.title }}%0A**PR 설명:** ${{ github.event.pull_request.body }}%0A**작성자:** @${{ github.event.pull_request.user.login }}%0A**브랜치:** ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}'
SLACK_USERNAME: RunCombi Android CI
SLACK_MESSAGE: |
🎉 RunCombi Android 빌드 성공!

📱 **앱 버전**: v${{ steps.app_version.outputs.version_name }} (${{ steps.app_version.outputs.version_code }})
🔗 **PR 제목**: ${{ github.event.pull_request.title }}
📝 **PR 내용**: ${{ github.event.pull_request.body || '내용이 없습니다.' }}
🚀 **GitHub Release**: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.app_version.outputs.version_name }}


- name: If Fail, Send notification on Slack
if: ${{failure()}}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_COLOR: '#ff0000'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_TITLE: 'RunCombi Android PR Check Failed ❌'
MSG_MINIMAL: true
SLACK_USERNAME: RunCombi Android
SLACK_MESSAGE: 'RunCombi Android PR 체크 실패 - 확인이 필요합니다 🔍 (v${{ steps.app_version.outputs.version_name }} - ${{ steps.app_version.outputs.version_code }})%0A%0A**PR 제목:** ${{ github.event.pull_request.title }}%0A**PR 설명:** ${{ github.event.pull_request.body }}%0A**작성자:** @${{ github.event.pull_request.user.login }}%0A**브랜치:** ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}'
22 changes: 21 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties

plugins {
id("runcombi.android.application")
alias(libs.plugins.google.services)
alias(libs.plugins.firebase.crashlytics)
}

android {
Expand Down Expand Up @@ -43,10 +45,17 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)

isDebuggable = false
}
debug {
isDebuggable = true
}
}

buildFeatures {
buildConfig = true
}

flavorDimensions += "mode"
productFlavors {
create("mock") {
Expand All @@ -63,6 +72,11 @@ dependencies {
implementation(libs.hilt.android)
implementation(libs.v2.user)

// Firebase
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
implementation(libs.firebase.crashlytics)

implementation(project(":feature:main"))
implementation(project(":feature:login"))
implementation(project(":feature:history"))
Expand All @@ -77,4 +91,10 @@ dependencies {
implementation(project(":core:data:walk"))
implementation(project(":core:data:history"))
implementation(project(":core:data:setting"))

// Test dependencies
testImplementation(libs.junit)
testImplementation(libs.kotlin.test)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
2 changes: 2 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
rootProject.name = "build-logic"

enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ configureHiltAndroid()
dependencies {
implementation(project(":core:designsystem"))
implementation(project(":core:navigation"))
implementation(project(":core:analytics"))
implementation(project(":core:ui"))
implementation(project(":core:domain:auth"))
implementation(project(":core:domain:common"))
Expand Down
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ plugins {
alias(libs.plugins.kotlin.plugin.serialization) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.google.services) apply false
alias(libs.plugins.firebase.crashlytics) apply false
}
1 change: 1 addition & 0 deletions core/analytics/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
Loading
Loading