From 96fc9cf697af33e33ca173f038f9539409df6cb1 Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 22:39:54 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20SplashActivity=20Handler=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0,=20SplashScreen=20API=20+=20ViewModel=20+=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - androidx.core:core-splashscreen 도입, windowBackground 방식 제거 - SplashViewModel: Handler → viewModelScope + delay, isReady/navigateEvent StateFlow/SharedFlow - SplashActivity: @AndroidEntryPoint + viewModels(), setKeepOnScreenCondition으로 splash 유지 - SplashViewModelTest: 4개 케이스 (초기값, 1초 전, 1초 후 isReady, navigateEvent emit) - activity_splash.xml 삭제 (빈 레이아웃) --- app/build.gradle | 1 + .../presentation/splash/SplashActivity.kt | 43 ++++++------- .../presentation/splash/SplashViewModel.kt | 36 +++++++++++ app/src/main/res/layout/activity_splash.xml | 9 --- app/src/main/res/values/themes.xml | 8 +-- .../splash/SplashViewModelTest.kt | 61 +++++++++++++++++++ gradle/libs.versions.toml | 2 + 7 files changed, 126 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt delete mode 100644 app/src/main/res/layout/activity_splash.xml create mode 100644 app/src/test/java/com/runnect/runnect/presentation/splash/SplashViewModelTest.kt diff --git a/app/build.gradle b/app/build.gradle index eaafa88ee..6d10a6235 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -137,6 +137,7 @@ dependencies { implementation libs.androidx.swiperefreshlayout implementation libs.androidx.preference.ktx implementation libs.androidx.security.crypto.ktx + implementation libs.androidx.splashscreen // Compose implementation platform(libs.compose.bom) diff --git a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt index c0192cdc2..cb342c3e4 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt @@ -2,35 +2,36 @@ package com.runnect.runnect.presentation.splash import android.content.Intent import android.os.Bundle -import android.os.Handler -import android.os.Looper import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import com.runnect.runnect.R +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.runnect.runnect.presentation.login.LoginActivity -import com.runnect.runnect.presentation.scheme.SchemeActivity - +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +@AndroidEntryPoint class SplashActivity : AppCompatActivity() { - private val handler = Handler(Looper.getMainLooper()) + private val viewModel: SplashViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge() + val splashScreen = installSplashScreen() + splashScreen.setKeepOnScreenCondition { !viewModel.isReady.value } super.onCreate(savedInstanceState) - setContentView(R.layout.activity_splash) - navigateToLoginScreen() - } - - private fun navigateToLoginScreen() { - handler.postDelayed({ - val intent = Intent(this, LoginActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) - startActivity(intent) - finish() - }, DELAY_TIME) - } + enableEdgeToEdge() - companion object { - private const val DELAY_TIME = 1000L + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.navigateEvent.collect { + startActivity(Intent(this@SplashActivity, LoginActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) + }) + finish() + } + } + } } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt new file mode 100644 index 000000000..115325f1d --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt @@ -0,0 +1,36 @@ +package com.runnect.runnect.presentation.splash + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SplashViewModel @Inject constructor() : ViewModel() { + + private val _isReady = MutableStateFlow(false) + val isReady: StateFlow = _isReady.asStateFlow() + + private val _navigateEvent = MutableSharedFlow(extraBufferCapacity = 1) + val navigateEvent: SharedFlow = _navigateEvent.asSharedFlow() + + init { + viewModelScope.launch { + delay(SPLASH_DELAY) + _isReady.value = true + _navigateEvent.emit(Unit) + } + } + + companion object { + const val SPLASH_DELAY = 1000L + } +} diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml deleted file mode 100644 index bcff2d717..000000000 --- a/app/src/main/res/layout/activity_splash.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d7f9d7df3..af7fdf083 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -29,10 +29,10 @@ @style/Widget.Runnect.EditText - diff --git a/app/src/test/java/com/runnect/runnect/presentation/splash/SplashViewModelTest.kt b/app/src/test/java/com/runnect/runnect/presentation/splash/SplashViewModelTest.kt new file mode 100644 index 000000000..11a4dfa7a --- /dev/null +++ b/app/src/test/java/com/runnect/runnect/presentation/splash/SplashViewModelTest.kt @@ -0,0 +1,61 @@ +package com.runnect.runnect.presentation.splash + +import app.cash.turbine.test +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class SplashViewModelTest { + private val testDispatcher = StandardTestDispatcher() + + @Before + fun setUp() { + Dispatchers.setMain(testDispatcher) + } + + @After + fun tearDown() { + Dispatchers.resetMain() + } + + @Test + fun `초기 상태에서 isReady는 false다`() { + val viewModel = SplashViewModel() + assertFalse(viewModel.isReady.value) + } + + @Test + fun `1초 경과 전에는 isReady가 false다`() = runTest(testDispatcher) { + val viewModel = SplashViewModel() + advanceTimeBy(SplashViewModel.SPLASH_DELAY - 1) + assertFalse(viewModel.isReady.value) + } + + @Test + fun `1초 경과 후 isReady가 true가 된다`() = runTest(testDispatcher) { + val viewModel = SplashViewModel() + advanceUntilIdle() + assertTrue(viewModel.isReady.value) + } + + @Test + fun `1초 후 navigateEvent가 emit된다`() = runTest(testDispatcher) { + val viewModel = SplashViewModel() + viewModel.navigateEvent.test { + advanceTimeBy(SplashViewModel.SPLASH_DELAY) + awaitItem() + cancelAndIgnoreRemainingEvents() + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 057211dc5..ea96cc8db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,7 @@ viewpager2 = "1.1.0" swiperefreshlayout = "1.2.0" preference-ktx = "1.2.1" security-crypto = "1.1.0" +splashscreen = "1.0.1" # Compose compose-bom = "2026.03.01" @@ -106,6 +107,7 @@ androidx-viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", vers androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" } androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preference-ktx" } androidx-security-crypto-ktx = { group = "androidx.security", name = "security-crypto-ktx", version.ref = "security-crypto" } +androidx-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashscreen" } # Compose compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } From 138f71d2405d924daca8597fe5834509a2ad47a8 Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 22:55:24 +0900 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20SplashViewModel=20navigateEvent=20re?= =?UTF-8?q?play=3D1=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(lifecycle=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=20=EC=8B=9C=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=9C=A0?= =?UTF-8?q?=EC=8B=A4=20=EB=B0=A9=EC=A7=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/runnect/runnect/presentation/splash/SplashViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt index 115325f1d..eaf9ea499 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashViewModel.kt @@ -19,7 +19,7 @@ class SplashViewModel @Inject constructor() : ViewModel() { private val _isReady = MutableStateFlow(false) val isReady: StateFlow = _isReady.asStateFlow() - private val _navigateEvent = MutableSharedFlow(extraBufferCapacity = 1) + private val _navigateEvent = MutableSharedFlow(replay = 1) val navigateEvent: SharedFlow = _navigateEvent.asSharedFlow() init { From 9d01dd8fa7b5737c167c2d40f3d170e4e6f9ae9d Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:07:34 +0900 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20SplashActivity=20Compose=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B8=B0=EC=A1=B4=20=EB=B9=84=EC=A3=BC=EC=96=BC=20?= =?UTF-8?q?=EB=B3=B5=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - windowSplashScreenAnimatedIcon 제거 (전체화면 이미지를 아이콘 슬롯에 잘못 사용한 것 수정) - SplashActivity에 setContent { SplashScreen() } 추가 — splash.webp를 Compose Image로 렌더링 - setKeepOnScreenCondition { false }로 시스템 스플래시 즉시 해제 후 Compose 화면 표시 - windowSplashScreenBackground = M1(보라)로 시스템 스플래시 → Compose 전환 시 색상 연속성 유지 --- .../presentation/splash/SplashActivity.kt | 7 ++++++- .../presentation/splash/SplashScreen.kt | 19 +++++++++++++++++++ app/src/main/res/values/themes.xml | 3 +-- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/runnect/runnect/presentation/splash/SplashScreen.kt diff --git a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt index cb342c3e4..3043f92fc 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashActivity.kt @@ -2,6 +2,7 @@ package com.runnect.runnect.presentation.splash import android.content.Intent import android.os.Bundle +import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity @@ -19,10 +20,14 @@ class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() - splashScreen.setKeepOnScreenCondition { !viewModel.isReady.value } + splashScreen.setKeepOnScreenCondition { false } super.onCreate(savedInstanceState) enableEdgeToEdge() + setContent { + SplashScreen() + } + lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.navigateEvent.collect { diff --git a/app/src/main/java/com/runnect/runnect/presentation/splash/SplashScreen.kt b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashScreen.kt new file mode 100644 index 000000000..b709bfd0a --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/presentation/splash/SplashScreen.kt @@ -0,0 +1,19 @@ +package com.runnect.runnect.presentation.splash + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import com.runnect.runnect.R + +@Composable +fun SplashScreen() { + Image( + painter = painterResource(id = R.drawable.splash), + contentDescription = null, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.FillBounds, + ) +} diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index af7fdf083..a97d5ccb6 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -30,8 +30,7 @@ From f147715ae0bd3d616ef4e6b8b6e1b253bb435b8a Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:21:33 +0900 Subject: [PATCH 4/8] =?UTF-8?q?test:=20SplashScreen=20Compose=20UI=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80=20(=EB=A0=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81=20=EC=95=88=EC=A0=84=EB=A7=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/splash/SplashScreenTest.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/src/androidTest/java/com/runnect/runnect/presentation/splash/SplashScreenTest.kt diff --git a/app/src/androidTest/java/com/runnect/runnect/presentation/splash/SplashScreenTest.kt b/app/src/androidTest/java/com/runnect/runnect/presentation/splash/SplashScreenTest.kt new file mode 100644 index 000000000..0a70dd76b --- /dev/null +++ b/app/src/androidTest/java/com/runnect/runnect/presentation/splash/SplashScreenTest.kt @@ -0,0 +1,21 @@ +package com.runnect.runnect.presentation.splash + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onRoot +import org.junit.Rule +import org.junit.Test + +class SplashScreenTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun `SplashScreen이_렌더링된다`() { + composeTestRule.setContent { + SplashScreen() + } + composeTestRule.onRoot().assertIsDisplayed() + } +} From 820aa9f17ba71cc0f3adeb96be0b2ce3469e5b8b Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:23:41 +0900 Subject: [PATCH 5/8] =?UTF-8?q?ci:=20PR=20=EB=B3=80=EA=B2=BD=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EA=B8=B0=EB=B0=98=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EC=A0=81=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 변경된 .kt 파일의 패키지를 추출해 --tests 필터 구성 - PR: 영향 범위 패키지 테스트만 실행 (unit + instrumented 동일 적용) - push to develop: 전체 테스트 실행 (안전망 유지) --- .github/workflows/CI.yml | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index d99b53971..69da6ea0d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -104,8 +104,29 @@ jobs: - name: Change gradlew permissions run: chmod +x ./gradlew + - name: Detect changed test packages + id: packages + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + PKGS=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \ + | grep -E "^app/src/(main|test|androidTest)/java/.+\.kt$" \ + | sed 's|app/src/[^/]*/java/||;s|/[^/]*\.kt$||;s|/|.|g' \ + | sort -u \ + | tr '\n' ' ') + echo "packages=$PKGS" >> "$GITHUB_OUTPUT" + else + echo "packages=" >> "$GITHUB_OUTPUT" + fi + - name: Run unit tests - run: ./gradlew testDebugUnitTest --stacktrace + run: | + PKGS="${{ steps.packages.outputs.packages }}" + if [ -z "$PKGS" ]; then + ./gradlew testDebugUnitTest --stacktrace + else + ARGS=$(echo "$PKGS" | tr ' ' '\n' | grep -v '^$' | sed 's/$/.*/;s/^/--tests /' | tr '\n' ' ') + ./gradlew testDebugUnitTest $ARGS --stacktrace + fi - name: Comment unit test failures on PR if: always() && github.event_name == 'pull_request' @@ -217,6 +238,20 @@ jobs: - name: Change gradlew permissions run: chmod +x ./gradlew + - name: Detect changed test packages + id: packages + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + PKGS=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \ + | grep -E "^app/src/(main|test|androidTest)/java/.+\.kt$" \ + | sed 's|app/src/[^/]*/java/||;s|/[^/]*\.kt$||;s|/|.|g' \ + | sort -u \ + | tr '\n' ' ') + echo "packages=$PKGS" >> "$GITHUB_OUTPUT" + else + echo "packages=" >> "$GITHUB_OUTPUT" + fi + - name: Enable KVM group perms run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -225,12 +260,20 @@ jobs: - name: Run Compose UI tests on emulator uses: reactivecircus/android-emulator-runner@v2 + env: + TEST_PACKAGES: ${{ steps.packages.outputs.packages }} with: api-level: 34 target: google_apis arch: x86_64 profile: pixel_6 - script: ./gradlew connectedDebugAndroidTest --stacktrace + script: | + if [ -z "$TEST_PACKAGES" ]; then + ./gradlew connectedDebugAndroidTest --stacktrace + else + ARGS=$(echo "$TEST_PACKAGES" | tr ' ' '\n' | grep -v '^$' | sed 's/$/.*/;s/^/--tests /' | tr '\n' ' ') + ./gradlew connectedDebugAndroidTest $ARGS --stacktrace + fi - name: Comment Compose UI test failures on PR if: always() && github.event_name == 'pull_request' From cd48d3d8cd46bad0fb911cf39ff464b3682163fe Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:28:27 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20CI=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B0=90=EC=A7=80=EB=A5=BC=20git=20diff=20=E2=86=92=20GitHub?= =?UTF-8?q?=20API=EB=A1=9C=20=EA=B5=90=EC=B2=B4=20(shallow=20clone=20?= =?UTF-8?q?=ED=98=B8=ED=99=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/CI.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 69da6ea0d..1a4bc8b1d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -106,9 +106,14 @@ jobs: - name: Detect changed test packages id: packages + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | if [ "${{ github.event_name }}" = "pull_request" ]; then - PKGS=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \ + PKGS=$(gh api "repos/$REPO/pulls/$PR_NUMBER/files" --paginate \ + --jq '.[].filename' \ | grep -E "^app/src/(main|test|androidTest)/java/.+\.kt$" \ | sed 's|app/src/[^/]*/java/||;s|/[^/]*\.kt$||;s|/|.|g' \ | sort -u \ @@ -240,9 +245,14 @@ jobs: - name: Detect changed test packages id: packages + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | if [ "${{ github.event_name }}" = "pull_request" ]; then - PKGS=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \ + PKGS=$(gh api "repos/$REPO/pulls/$PR_NUMBER/files" --paginate \ + --jq '.[].filename' \ | grep -E "^app/src/(main|test|androidTest)/java/.+\.kt$" \ | sed 's|app/src/[^/]*/java/||;s|/[^/]*\.kt$||;s|/|.|g' \ | sort -u \ From 4c8be96b2b5cc82c745c919148b0a10f6584c5ee Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:32:24 +0900 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20emulator-runner=20script=EB=A5=BC=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=20=ED=8C=8C=EC=9D=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20(sh=20=EB=A9=80=ED=8B=B0=EB=9D=BC=EC=9D=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/scripts/run_android_tests.sh | 10 ++++++++++ .github/workflows/CI.yml | 8 +------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 .github/scripts/run_android_tests.sh diff --git a/.github/scripts/run_android_tests.sh b/.github/scripts/run_android_tests.sh new file mode 100644 index 000000000..a8a3d4e8e --- /dev/null +++ b/.github/scripts/run_android_tests.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +PKGS="${TEST_PACKAGES:-}" +if [ -z "$PKGS" ]; then + ./gradlew connectedDebugAndroidTest --stacktrace +else + ARGS=$(echo "$PKGS" | tr ' ' '\n' | grep -v '^$' | sed 's/$/.*/;s/^/--tests /' | tr '\n' ' ') + ./gradlew connectedDebugAndroidTest $ARGS --stacktrace +fi diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1a4bc8b1d..ab8801676 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -277,13 +277,7 @@ jobs: target: google_apis arch: x86_64 profile: pixel_6 - script: | - if [ -z "$TEST_PACKAGES" ]; then - ./gradlew connectedDebugAndroidTest --stacktrace - else - ARGS=$(echo "$TEST_PACKAGES" | tr ' ' '\n' | grep -v '^$' | sed 's/$/.*/;s/^/--tests /' | tr '\n' ' ') - ./gradlew connectedDebugAndroidTest $ARGS --stacktrace - fi + script: bash .github/scripts/run_android_tests.sh - name: Comment Compose UI test failures on PR if: always() && github.event_name == 'pull_request' From 47689c817be94c0a675a3179195c8c505c3c32b0 Mon Sep 17 00:00:00 2001 From: unam98 Date: Fri, 26 Jun 2026 23:38:39 +0900 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20connectedDebugAndroidTest=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=ED=95=84=ED=84=B0=20=EC=9D=B8?= =?UTF-8?q?=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --tests는 JVM 전용 옵션으로 connectedDebugAndroidTest에선 지원 안 됨. -Pandroid.testInstrumentationRunnerArguments.package 로 교체. --- .github/scripts/run_android_tests.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/scripts/run_android_tests.sh b/.github/scripts/run_android_tests.sh index a8a3d4e8e..ff93eeb7f 100644 --- a/.github/scripts/run_android_tests.sh +++ b/.github/scripts/run_android_tests.sh @@ -5,6 +5,9 @@ PKGS="${TEST_PACKAGES:-}" if [ -z "$PKGS" ]; then ./gradlew connectedDebugAndroidTest --stacktrace else - ARGS=$(echo "$PKGS" | tr ' ' '\n' | grep -v '^$' | sed 's/$/.*/;s/^/--tests /' | tr '\n' ' ') - ./gradlew connectedDebugAndroidTest $ARGS --stacktrace + # connectedDebugAndroidTest uses runner args for filtering, not --tests + PKG_FILTER=$(echo "$PKGS" | tr ' ' '\n' | grep -v '^$' | tr '\n' ',' | sed 's/,$//') + ./gradlew connectedDebugAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.package="$PKG_FILTER" \ + --stacktrace fi