Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 18 additions & 5 deletions .github/ci-gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Disable daemon for CI to avoid memory leaks, but enable parallel execution
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.workers.max=2

kotlin.incremental=false
# Increase worker count for CI (GitHub runners have 4 cores)
org.gradle.workers.max=4
# Enable Kotlin incremental compilation in CI (faster on repeated builds)
kotlin.incremental=true
kotlin.compiler.execution.strategy=in-process

# Build cache optimizations
org.gradle.caching=true
org.gradle.configuration-cache=true
# JVM memory settings for CI
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
# Android build optimizations
android.useAndroidX=true
android.enableJetifier=false
android.nonTransitiveRClass=true
android.nonFinalResIds=true
# Kotlin compiler optimizations
kotlin.daemon.jvm.options=-Xmx2048m
kotlin.code.style=official
# Controls KotlinOptions.allWarningsAsErrors.
# This value used in CI and is currently set to false.
# If you want to treat warnings as errors locally, set this property to true
Expand Down
46 changes: 25 additions & 21 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,23 @@ jobs:
needs: cancel-previous
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
uses: gradle/actions/wrapper-validation@v5
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}

Copilot AI Oct 23, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache-encryption-key parameter requires a secret to be configured in the repository settings. Add a note in the PR description or documentation explaining that GRADLE_ENCRYPTION_KEY must be set up in GitHub repository secrets before this workflow will function correctly.

Suggested change
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
# NOTE: The cache-encryption-key parameter requires the GRADLE_ENCRYPTION_KEY secret to be configured
# in the repository settings. Please ensure that GRADLE_ENCRYPTION_KEY is set in GitHub repository secrets
# before this workflow will function correctly.

Copilot uses AI. Check for mistakes.
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
- name: Lint
run: ./gradlew lintDebug --build-cache --parallel --configure-on-demand
run: ./gradlew lintDebug --build-cache --parallel --configure-on-demand --configuration-cache
- name: Upload Lint Reports
if: always()
uses: actions/upload-artifact@v4
Expand All @@ -62,25 +63,26 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
needs: lint
needs: cancel-previous
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
- name: Build APK
run: ./gradlew assembleDebug --build-cache --parallel --configure-on-demand
run: ./gradlew assembleDebug --build-cache --parallel --configure-on-demand --configuration-cache
- name: Build Bundle
run: ./gradlew bundleDebug --build-cache --parallel --configure-on-demand
run: ./gradlew bundleDebug --build-cache --parallel --configure-on-demand --configuration-cache
- name: Upload APK
uses: actions/upload-artifact@v4
with:
Expand All @@ -101,23 +103,24 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
needs: build
needs: cancel-previous
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
- name: Run Unit Tests
run: ./gradlew testDebugUnitTest --build-cache --parallel --configure-on-demand
run: ./gradlew testDebugUnitTest --build-cache --parallel --configure-on-demand --configuration-cache
- name: Upload Test Reports
if: always()
uses: actions/upload-artifact@v4
Expand All @@ -134,7 +137,7 @@ jobs:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 45
needs: test
needs: [ lint, build, test ]
if: |
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop' ||
Expand All @@ -144,18 +147,19 @@ jobs:
api-level: [ 34 ]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
# Enable KVM for hardware acceleration on Ubuntu runners (required for Android Emulator performance)
- name: Enable KVM group perms
run: |
Expand Down Expand Up @@ -191,7 +195,7 @@ jobs:
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: ./gradlew connectedDebugAndroidTest --build-cache --parallel --configure-on-demand
script: ./gradlew connectedDebugAndroidTest --build-cache --parallel --configure-on-demand --configuration-cache
- name: Upload Instrumented Test Reports
if: always()
uses: actions/upload-artifact@v4
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,29 @@ To Implement chai,

See the example implementation that exists by running [chaidemo] that contains the various implementations of the elements of the design system.

## CI/CD Quick Start

The project uses GitHub Actions for continuous integration with optimized parallel execution and
caching.

**Quick commands to test locally:**

```bash
# Run all checks (matches CI)
./gradlew clean lintDebug assembleDebug testDebugUnitTest --configuration-cache

# Trigger instrumented tests on PR
git commit -m "Your message [test-instrumented]"
```

📖 **See [CI Quick Start Guide](./docs/quick-start-ci.md)** for complete local development setup and
troubleshooting.

For detailed optimization information, see:

- [CI Workflow Guide](./docs/ci-workflow-guide.md) - Job structure and timing
- [CI Build Optimization](./docs/ci-build-optimization.md) - Performance details

### [Running Project]
Known issue with gradle:
- If you run into an error when building project, ist probably a false negative.
Expand Down
16 changes: 16 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,19 @@ plugins {
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.jetbrains.compose) apply false
}

// Apply performance optimizations to all subprojects
subprojects {
tasks.withType<JavaCompile>().configureEach {
options.isIncremental = true
}

// Skip unnecessary tasks in CI
//See if i can add this to build Logic
tasks.matching {
it.name.contains("lint", ignoreCase = true) &&
it.name.contains("Baseline", ignoreCase = true)
}.configureEach {
enabled = System.getenv("CI") != "true"
}
}
16 changes: 13 additions & 3 deletions chai/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,20 @@ android {
"proguard-rules.pro"
)
}
// Optimize debug builds for CI
//See if i can add this to build Logic
debug {
isMinifyEnabled = false
}
}

// Disable BuildConfig generation for library (not needed, saves build time)
//See if i can add this to build Logic
Comment on lines +43 to +50

Copilot AI Oct 23, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment 'See if i can add this to build Logic' should be either removed or converted to a proper TODO comment. If this is a planned refactoring, use // TODO: Move to build logic for better tracking.

Suggested change
//See if i can add this to build Logic
debug {
isMinifyEnabled = false
}
}
// Disable BuildConfig generation for library (not needed, saves build time)
//See if i can add this to build Logic
// TODO: Move to build logic
debug {
isMinifyEnabled = false
}
}
// Disable BuildConfig generation for library (not needed, saves build time)
// TODO: Move to build logic

Copilot uses AI. Check for mistakes.
buildFeatures {
buildConfig = false
compose = true
}
Comment on lines +49 to 54

Copilot AI Oct 23, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment 'See if i can add this to build Logic' should be either removed or converted to a proper TODO comment. If this is a planned refactoring, use // TODO: Move to build logic for better tracking.

Copilot uses AI. Check for mistakes.

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
Expand All @@ -49,9 +62,6 @@ android {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
}
}
buildFeatures {
compose = true
}

composeOptions {
kotlinCompilerExtensionVersion = "1.5.15"
Expand Down
4 changes: 4 additions & 0 deletions chaidemo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ android {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
getByName("debug") {
isMinifyEnabled = false
}
}

compileOptions {
Expand All @@ -57,6 +60,7 @@ android {

buildFeatures {
compose = true
buildConfig = false
}

composeOptions {
Expand Down
101 changes: 101 additions & 0 deletions docs/ci-build-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# CI Build Time Optimization Guide

## 🔧 Additional Optimizations to be applied

### **1. Skip Unnecessary Tasks**

Add to `build.gradle.kts`:

```kotlin
tasks.withType<JavaCompile>().configureEach {
options.isIncremental = true
}

// Skip tasks not needed in CI
tasks.matching {
it.name.startsWith("generate") &&
it.name.endsWith("BuildConfig")
}.configureEach {
enabled = !System.getenv("CI").toBoolean()
}
```


### **3. Optimize Dependencies**

```kotlin
// Use implementation instead of api when possible
implementation(libs.androidx.core.ktx) // ✅ Better
api(libs.androidx.core.ktx) // ❌ Slower (forces recompilation)

// Use compileOnly for large dependencies not needed at runtime
compileOnly(libs.some.large.library)
```

### **4. Enable R8/ProGuard Optimization in CI**

```kotlin
buildTypes {
debug {
// Disable minification in debug for faster CI builds
isMinifyEnabled = false
}
}
```

---

## 🎯 Monitoring Build Performance


## 🔍 Troubleshooting

### **Build slower after optimization?**

**Check:**

1. Configuration cache warnings: `./gradlew --configuration-cache help`
2. Gradle cache hits: Look for "FROM-CACHE" in logs
3. Parallel execution: Check if tasks run simultaneously

**Common issues:**

- Configuration cache problems with custom plugins
- Tasks not cacheable (check `@CacheableTask` annotations)
- Too many workers (reduce if memory issues)

### **Configuration cache errors?**

```bash
# Locally test configuration cache
./gradlew clean build --configuration-cache

# If errors, disable temporarily
./gradlew build --no-configuration-cache
```

### **Out of memory errors?**

Increase memory in `ci-gradle.properties`:

```properties
org.gradle.jvmargs=-Xmx6144m # Increase from 4GB to 6GB
```

---

## 📈 Future Improvements

Consider these for even faster builds:

- [ ] **Split workflows**: Separate lint/test/build into different workflow files
- [ ] **Matrix builds**: Build multiple variants in parallel

---

## 🎓 Learn More

- [Gradle Performance Guide](https://docs.gradle.org/current/userguide/performance.html)
- [Configuration Cache](https://docs.gradle.org/current/userguide/configuration_cache.html)
- [GitHub Actions Optimization](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
- [Android Build Performance](https://developer.android.com/studio/build/optimize-your-build)
Loading
Loading