🔧 :: (#131) - Build Variants 구성 및 Debug 환경 분리#132
Conversation
debug/release buildType을 확장하여 추후 Amplitude 도입 시 개발 로그와 상용 로그를 분리할 수 있는 기반을 구축한다. - convention plugin에 buildFeatures.buildConfig = true 활성화 - debug: applicationIdSuffix ".dev", AMPLITUDE_API_KEY placeholder, 앱이름 "(Dev)" - release: AMPLITUDE_API_KEY placeholder, 앱이름 "오늘 뭐임" - app strings.xml의 app_name을 resValue로 대체 Constraint: Product flavor 없이 기존 buildType만 활용 Constraint: convention plugin은 구조적 설정만, 값 수준 설정은 app 모듈 Rejected: Product flavor 사용 | buildType만으로 충분, 불필요한 복잡도 Rejected: Convention plugin에 모든 설정 통합 | app-specific 값이 convention에 혼입되어 단일 책임 위반 Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
개별 파일 나열 방식에서 .idea/ 일괄 ignore로 변경하여 IDE 생성 파일이 새로 추가될 때마다 누락되는 문제를 해결한다. - .gitignore에서 /.idea/* 개별 항목 제거 후 .idea/ 로 단일화 - 기존에 트래킹되던 .idea/.gitignore 제거 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Release variant 선택 시 signingConfig 미지정으로 APK 서명이 실패하던 문제를 해결하고, BuildType resValue 도입 이후 남아있던 라이브러리 모듈의 중복 app_name 리소스를 제거한다. - app 모듈에 local.properties 기반 release signingConfig 추가 - STORE_FILE 미설정 시 debug 서명으로 fallback 하여 타 개발자도 빌드 가능 - feature/root strings.xml의 app_name 제거 (app 모듈 resValue로 단일화) Constraint: 키스토어 자격증명은 local.properties로만 주입 (커밋 금지) Rejected: Release를 무조건 debug 서명 | 실제 배포 빌드 불가 Rejected: 환경변수만 사용 | 로컬 개발 UX 저하 Confidence: high Scope-risk: narrow Directive: local.properties에 STORE_FILE/STORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD 설정 필요 Not-tested: 실제 keystore로 서명된 release APK 설치 검증 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Release variant와 육안으로 구분이 어려워 실수를 유발하던 문제를 해결하기 위해 debug 빌드에서만 노출되는 상단 리본을 추가한다. - ApplicationInfo.FLAG_DEBUGGABLE로 debug 여부 감지 (BuildConfig 의존 제거) - NavHost 위에 zIndex 최상단으로 오버레이하여 모든 화면에서 노출 - release 빌드에서는 Composable 자체가 미포함되어 런타임 비용 없음 Constraint: feature/root는 라이브러리 모듈이라 app의 BuildConfig를 직접 못 씀 Rejected: feature/root에 buildConfig = true 활성화 | 전파 범위 대비 이득 적음 Rejected: Toast/Snackbar로 표시 | 상시 식별 불가 Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 23 minutes and 51 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Walkthrough빌드 설정에 release 서명 로직과 buildConfig 생성을 추가하고, 정적 Changes
Sequence Diagram(s)sequenceDiagram
participant Gradle
participant FS as FileSystem
participant BuildLogic as "Build Logic/Plugin"
participant AndroidBuild as "Android BuildTypes"
participant App as "Runtime (MainActivity)"
Gradle->>FS: 읽기 local.properties (STORE_FILE 등)
Gradle->>BuildLogic: 적용(빌드피처 buildConfig)
Gradle->>AndroidBuild: 생성 signingConfig release (파일 존재 검사)
AndroidBuild-->>Gradle: signingConfig 설정 / 에러 발생 가능
Gradle->>AndroidBuild: buildTypes 설정 (debug/release: AMPLITUDE_API_KEY, app_name)
Gradle->>App: 빌드 산출물 (빌드타입에 따라 값 포함)
App->>App: 런타임에서 applicationInfo.flags로 isDebuggable 판정
alt isDebuggable == true
App->>App: DebugRibbon 렌더링 (상단)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
feature/root/src/main/java/khs/onmi/root/MainActivity.kt (2)
90-90: 디버그 리본 텍스트도 리소스로 분리해 두는 것을 권장합니다.Line 90의
"DEBUG"하드코딩은 당장 문제는 없지만, 테스트/현지화/문구 변경 대응을 위해stringResource사용이 유지보수에 유리합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/root/src/main/java/khs/onmi/root/MainActivity.kt` at line 90, Replace the hardcoded "DEBUG" in MainActivity.kt (the text = "DEBUG" argument) with a string resource: add a new entry (e.g., <string name="debug_label">DEBUG</string>) to your strings.xml and use stringResource(R.string.debug_label) for the text parameter (ensure you import androidx.compose.ui.res.stringResource). This keeps the label localizable and easier to change in the future.
44-44:BuildConfig.DEBUG로 디버그 판별 로직 변경 권장현재
ApplicationInfo.FLAG_DEBUGGABLE를 사용한 런타임 판별 대신, 컴파일 타임에 결정되는BuildConfig.DEBUG를 사용하는 것이 더 명확하고 효율적입니다. 특히 빌드타입 기준 분리를 목표로 하는 이 PR에서는 더욱 그렇습니다.제안 diff
-import android.content.pm.ApplicationInfo @@ - val isDebuggable = applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0 + val isDebuggable = BuildConfig.DEBUG🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/root/src/main/java/khs/onmi/root/MainActivity.kt` at line 44, Replace the runtime check using ApplicationInfo.FLAG_DEBUGGABLE with the compile-time flag BuildConfig.DEBUG: find the isDebuggable variable in MainActivity (the line declaring "isDebuggable" and referencing ApplicationInfo.FLAG_DEBUGGABLE), change it to use BuildConfig.DEBUG instead, and remove any now-unused applicationInfo/PackageManager logic or imports related to the flag; ensure references that depend on isDebuggable continue to work with the boolean BuildConfig.DEBUG.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/build.gradle.kts`:
- Around line 24-31: The release signing block currently proceeds if STORE_FILE
exists but doesn't validate STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD or that the
file actually exists; update the logic around
storeFilePath/storeFile/storePassword/keyAlias/keyPassword to validate all
required properties and the file path and fail fast (e.g., throw a
GradleException) when any of storePassword, keyAlias, keyPassword are missing or
when rootProject.file(storeFilePath) does not exist or is not a file so the
build aborts with a clear error message instead of continuing with an incomplete
signing configuration.
- Around line 43-47: The current signingConfig assignment silently falls back to
the debug key when STORE_FILE is missing; instead, detect when a release-related
build is being requested (e.g., inspect gradle.startParameter.taskNames for
"Release"/"assembleRelease"/"bundleRelease" or check buildType.name ==
"release") and throw a GradleException if STORE_FILE (or any required release
signing property) is absent; update the signingConfig logic around signingConfig
= ... to explicitly fail for release builds rather than selecting
signingConfigs.getByName("debug"), and keep the fallback to debug only for
non-release tasks.
---
Nitpick comments:
In `@feature/root/src/main/java/khs/onmi/root/MainActivity.kt`:
- Line 90: Replace the hardcoded "DEBUG" in MainActivity.kt (the text = "DEBUG"
argument) with a string resource: add a new entry (e.g., <string
name="debug_label">DEBUG</string>) to your strings.xml and use
stringResource(R.string.debug_label) for the text parameter (ensure you import
androidx.compose.ui.res.stringResource). This keeps the label localizable and
easier to change in the future.
- Line 44: Replace the runtime check using ApplicationInfo.FLAG_DEBUGGABLE with
the compile-time flag BuildConfig.DEBUG: find the isDebuggable variable in
MainActivity (the line declaring "isDebuggable" and referencing
ApplicationInfo.FLAG_DEBUGGABLE), change it to use BuildConfig.DEBUG instead,
and remove any now-unused applicationInfo/PackageManager logic or imports
related to the flag; ensure references that depend on isDebuggable continue to
work with the boolean BuildConfig.DEBUG.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 48a29d01-c92f-4997-9598-42205d91ed11
📒 Files selected for processing (7)
.gitignore.idea/.gitignoreapp/build.gradle.ktsapp/src/main/res/values/strings.xmlbuild-logic/convention/src/main/java/khs/onmi/convention/AndroidApplicationConventionPlugin.ktfeature/root/src/main/java/khs/onmi/root/MainActivity.ktfeature/root/src/main/res/values/strings.xml
💤 Files with no reviewable changes (2)
- feature/root/src/main/res/values/strings.xml
- .idea/.gitignore
There was a problem hiding this comment.
Code Review
This pull request introduces build-type specific configurations, including signing configurations and application names, by loading properties from local.properties. It also adds a visual "DEBUG" ribbon to the MainActivity when the app is running in a debuggable state. Feedback focuses on optimizing property access in Gradle, refining the zIndex value for the debug ribbon to a more reasonable level, and avoiding hardcoded color values in the UI components.
feature/root의 verifyReleaseResources가 @string/app_name을 찾지 못해 CI에서 실패하던 문제를 해결한다. activity 레벨 label을 제거하고 app 모듈의 application 레벨 label(resValue)을 상속하도록 변경. - feature/root AndroidManifest의 activity android:label 제거 - app 모듈 application 레벨 label이 activity에 상속되어 BuildType별 resValue 정상 반영 Constraint: 라이브러리는 단독 빌드 시 자기 리소스만 링킹 검증 가능 Rejected: feature/root strings.xml에 fallback app_name 재추가 | 리소스 중복 및 유지보수 부담 Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CodeRabbit/Gemini 리뷰 피드백을 반영하여 release 서명 유효성 검증을 강화하고, DebugRibbon 구현 세부를 정리한다. - signingConfigs.release: STORE_FILE 외 PASSWORD/ALIAS 전체 검증, require로 fail-fast - buildTypes.release: release 태스크 실행 중 서명값 미설정 시 error로 명시 실패 - hasReleaseSigning/isReleaseTaskRequested 상위 변수로 중복 호출 제거 - DebugRibbon zIndex(Float.MAX_VALUE) → zIndex(1f)로 완화 - 하드코딩 색상값을 DebugRibbonBackgroundColor 파일 상수로 분리 Constraint: 로컬 debug 실행 UX는 유지하되 release 배포 리스크만 차단 Rejected: DebugRibbon 색상을 디자인 시스템에 추가 | 프로덕션 토큰과 책임 혼입 Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
app/build.gradle.kts (1)
15-16:⚠️ Potential issue | 🟠 MajorLine 65의 debug fallback은 집계 태스크 경로에서 그대로 남습니다.
isReleaseTaskRequested가 시작 태스크명에"Release"가 들어갈 때만 true라서,build/assemble같은 lifecycle task 경로에서는 Line 65의signingConfigs.debugfallback이 여전히 선택될 수 있습니다. Gradle의build는assemble에 의존하고assemble은 산출물 생성 태스크를 모으는 lifecycle task이며, Android 문서도 release 산출물은 signing config를 명시하지 않으면 기본적으로 unsigned라고 설명합니다. 그래서 여기서는 debug 키로 fallback하기보다signingConfig를 비워 두거나, 실제 release 산출물 요청에서만 명시적으로 실패시키는 편이 더 안전합니다. (docs.gradle.org)In Android Gradle Plugin for an application module, do `./gradlew build` or `./gradlew assemble` include release artifacts even when `gradle.startParameter.taskNames` is only `build` or `assemble`?Also applies to: 59-65
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/build.gradle.kts` around lines 15 - 16, isReleaseTaskRequested currently looks at startParameter.taskNames which misses lifecycle tasks like build/assemble and causes signingConfigs.debug to be used as a fallback; change the detection to inspect the actual task graph (use gradle.taskGraph.whenReady and check task names for "Release") and then only set signingConfig (instead of defaulting to signingConfigs.debug) when a real Release task is present; update places referencing signingConfigs.debug and signingConfig so they leave signingConfig null for non-explicit release builds and only fail or require a release signing config when the taskGraph indicates a Release task was requested (refer to isReleaseTaskRequested, signingConfigs.debug, signingConfig, and use gradle.taskGraph.whenReady).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/build.gradle.kts`:
- Around line 14-16: hasReleaseSigning currently only checks STORE_FILE causing
the require(...) checks in the signing configuration (lines referenced 28-40) to
run during configuration and break non-release builds; change hasReleaseSigning
to verify STORE_FILE, STORE_PASSWORD, KEY_ALIAS and KEY_PASSWORD are non-blank,
and wrap the signing require(...) calls / signingConfigs setup so they only
execute when a release task is actually requested (use isReleaseTaskRequested) —
i.e., only configure release signing if isReleaseTaskRequested is true and
hasReleaseSigning is true, otherwise skip the require checks so debug/other
tasks aren't blocked.
---
Duplicate comments:
In `@app/build.gradle.kts`:
- Around line 15-16: isReleaseTaskRequested currently looks at
startParameter.taskNames which misses lifecycle tasks like build/assemble and
causes signingConfigs.debug to be used as a fallback; change the detection to
inspect the actual task graph (use gradle.taskGraph.whenReady and check task
names for "Release") and then only set signingConfig (instead of defaulting to
signingConfigs.debug) when a real Release task is present; update places
referencing signingConfigs.debug and signingConfig so they leave signingConfig
null for non-explicit release builds and only fail or require a release signing
config when the taskGraph indicates a Release task was requested (refer to
isReleaseTaskRequested, signingConfigs.debug, signingConfig, and use
gradle.taskGraph.whenReady).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d93cbeb2-67db-4d3e-a242-bbdef5af746b
📒 Files selected for processing (3)
app/build.gradle.ktsfeature/root/src/main/AndroidManifest.xmlfeature/root/src/main/java/khs/onmi/root/MainActivity.kt
💤 Files with no reviewable changes (1)
- feature/root/src/main/AndroidManifest.xml
🚧 Files skipped from review as they are similar to previous changes (1)
- feature/root/src/main/java/khs/onmi/root/MainActivity.kt
| val hasReleaseSigning = !localProperties.getProperty("STORE_FILE").isNullOrBlank() | ||
| val isReleaseTaskRequested = gradle.startParameter.taskNames | ||
| .any { it.contains("Release", ignoreCase = true) } |
There was a problem hiding this comment.
불완전한 서명 설정이 debug 빌드까지 막습니다.
hasReleaseSigning이 STORE_FILE만 기준이라서, 경로만 남아 있고 비밀번호/alias가 비어 있어도 Line 28-40의 require(...)가 구성 단계에서 바로 실행됩니다. Gradle은 build.gradle(.kts)를 task 실행 전에 configuration phase에서 평가하므로, 이 상태면 assembleDebug 같은 release가 아닌 요청도 같이 깨집니다. 네 값이 모두 준비됐을 때만 release signing을 구성하고, 누락 에러는 실제 release 산출물을 만들 때만 내는 쪽이 안전합니다. (docs.gradle.org)
Also applies to: 28-40
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/build.gradle.kts` around lines 14 - 16, hasReleaseSigning currently only
checks STORE_FILE causing the require(...) checks in the signing configuration
(lines referenced 28-40) to run during configuration and break non-release
builds; change hasReleaseSigning to verify STORE_FILE, STORE_PASSWORD, KEY_ALIAS
and KEY_PASSWORD are non-blank, and wrap the signing require(...) calls /
signingConfigs setup so they only execute when a release task is actually
requested (use isReleaseTaskRequested) — i.e., only configure release signing if
isReleaseTaskRequested is true and hasReleaseSigning is true, otherwise skip the
require checks so debug/other tasks aren't blocked.
검증/폴백 분기를 제거하고 local.properties 값을 그대로 주입하는 직관적인 구조로 변경한다. release 빌드는 local.properties의 STORE_FILE/STORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD에 전적으로 의존한다. - signingConfigs.release: local.properties 값 직접 할당 (조건·검증 제거) - buildTypes.release: 조건 없이 release 서명 설정 고정 - isReleaseTaskRequested 가드 및 debug fallback 분기 제거 Constraint: local.properties에 서명 값이 없으면 Gradle configuration에서 실패 Rejected: 조건부 가드 유지 | 로직 복잡도 대비 얻는 이득이 적음 Confidence: medium Scope-risk: moderate Directive: CI는 local.properties 및 keystore 바이너리를 빌드 전에 준비해야 함 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
signingConfig가 local.properties 값에 무조건 의존하도록 변경되면서 CI에서 Gradle configuration 단계 자체가 실패하던 문제를 해결한다. - KEYSTORE_BASE64 secret을 base64 디코딩하여 keystore/onmi로 복원 - STORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD secret을 local.properties로 주입 - STORE_FILE 경로는 CI에서 고정(keystore/onmi) Constraint: secret 값이 CI 로그에 평문 노출되지 않도록 직접 echo 지양 Rejected: 조건부 가드 복구 | app 모듈 빌드 설정을 단순하게 유지하기 위함 Confidence: high Scope-risk: narrow Directive: 저장소 Secrets에 KEYSTORE_BASE64/STORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD 등록 필요 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💡 개요
📃 작업내용
AndroidApplicationConventionPlugin에buildFeatures.buildConfig = true활성화applicationIdSuffix = ".dev",AMPLITUDE_API_KEYplaceholder, 앱 이름오늘 뭐임 (Dev)AMPLITUDE_API_KEYplaceholder, 앱 이름오늘 뭐임app/strings.xml의app_name을 BuildType별resValue로 대체local.properties기반 ReleasesigningConfig추가 (STORE_FILE미설정 시 debug 서명으로 fallback)MainActivity에FLAG_DEBUGGABLE감지 기반 상단 DEBUG 리본 오버레이 (zIndex최상단)🔀 변경사항
.gitignore정리: 개별/.idea/*나열 제거 후.idea/단일 ignore로 변경.idea/.gitignore제거feature/root/strings.xml의 중복app_name리소스 제거 (app 모듈resValue로 단일화)🎸 기타
local.properties에STORE_FILE,STORE_PASSWORD,KEY_ALIAS,KEY_PASSWORD설정 필요Summary by CodeRabbit
릴리스 노트
New Features
Chores