Skip to content

Commit

Permalink
Merge branch 'main' into kotlin-2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonMarquis authored Mar 26, 2024
2 parents 4534d7a + 88c3eb0 commit 0c8f105
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 92 deletions.
13 changes: 11 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
Thanks for submitting a pull request. Please include the following information.
_Thanks for submitting a pull request. Please include the following information._

**What I have done and why**
Include a summary of what your pull request contains, and why you have made these changes.

_Include a summary of what your pull request contains, and why you have made these changes._

Fixes #<issue_number_goes_here>

**How I'm testing it**

_Choose at least one:_
- Unit tests
- UI tests
- Screenshot tests
- N/A _(provide justification)_

**Do tests pass?**
- [ ] Run local tests on `DemoDebug` variant: `./gradlew testDemoDebug`
- [ ] Check formatting: `./gradlew --init-script gradle/init.gradle.kts spotlessApply`
Expand Down
45 changes: 38 additions & 7 deletions .github/workflows/Build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:

permissions:
contents: write
pull-requests: write

timeout-minutes: 60

Expand Down Expand Up @@ -105,12 +106,13 @@ jobs:
commit_message: "🤖 Updates screenshots"

# Run local tests after screenshot tests to avoid wrong UP-TO-DATE. TODO: Ignore screenshots.
- name: Run local tests
- name: Run local tests and create report
if: always()
run: ./gradlew testDemoDebug :lint:test -Pksp.useKSP2=${{ matrix.useKSP2 }} -Pandroid.lint.useK2Uast=${{ matrix.useK2Uast }} -Pandroid.experimental.lint.version=8.5.0-alpha02
# Replace task exclusions with `-Pandroidx.baselineprofile.skipgeneration` when
# https://android-review.googlesource.com/c/platform/frameworks/support/+/2602790 landed in a
# release build

- name: Build all build type and flavor permutations
run: ./gradlew :app:assemble :benchmarks:assemble
-x pixel6Api33ProdNonMinifiedReleaseAndroidTest
Expand All @@ -125,11 +127,11 @@ jobs:
name: APKs-${{ matrix.useKSP2 }}-${{ matrix.useK2Uast }}
path: '**/build/outputs/apk/**/*.apk'

- name: Upload test results (XML)
- name: Upload JVM local results (XML)
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.useKSP2 }}-${{ matrix.useK2Uast }}
name: local-test-results-${{ matrix.useKSP2 }}-${{ matrix.useK2Uast }}
path: '**/build/test-results/test*UnitTest/**.xml'

- name: Check lint
Expand Down Expand Up @@ -186,10 +188,7 @@ jobs:
- name: Setup Gradle
uses: gradle/gradle-build-action@v3

- name: Build projects before running emulator
run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest

- name: Run instrumentation tests
- name: Build projects and run instrumentation tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
Expand All @@ -199,9 +198,41 @@ jobs:
heap-size: 600M
script: ./gradlew connectedDemoDebugAndroidTest --daemon

- name: Run local tests (including Roborazzi) for the combined coverage report (only API 30)
if: matrix.api-level == 30
# There is no need to verify Roborazzi tests to generate coverage.
run: ./gradlew testDemoDebugUnitTest -Proborazzi.test.verify=false # Add Prod if we ever add JVM tests for prod

# Add `createProdDebugUnitTestCoverageReport` if we ever add JVM tests for prod
- name: Generate coverage reports for Debug variants (only API 30)
if: matrix.api-level == 30
run: ./gradlew createDemoDebugCombinedCoverageReport

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.api-level }}
path: '**/build/reports/androidTests'

- name: Display local test coverage (only API 30)
if: matrix.api-level == 30
id: jacoco
uses: madrapps/[email protected]
with:
title: Combined test coverage report
min-coverage-overall: 40
min-coverage-changed-files: 60
paths: |
${{ github.workspace }}/**/build/reports/jacoco/**/*Report.xml
token: ${{ secrets.GITHUB_TOKEN }}

- name: Upload local coverage reports (XML + HTML) (only API 30)
if: matrix.api-level == 30
uses: actions/upload-artifact@v4
with:
name: coverage-reports
if-no-files-found: error
compression-level: 1
overwrite: false
path: '**/build/reports/jacoco/'
2 changes: 1 addition & 1 deletion app-nia-catalog/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ android {
// To publish on the Play store a private signing key is required, but to allow anyone
// who clones the code to sign and run the release variant, use the debug signing key.
// TODO: Abstract the signing configuration to a separate file to avoid hardcoding this.
signingConfig = signingConfigs.getByName("debug")
signingConfig = signingConfigs.named("debug").get()
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ plugins {
alias(libs.plugins.nowinandroid.android.application.flavors)
alias(libs.plugins.nowinandroid.android.application.jacoco)
alias(libs.plugins.nowinandroid.android.hilt)
id("jacoco")
alias(libs.plugins.nowinandroid.android.application.firebase)
id("com.google.android.gms.oss-licenses-plugin")
alias(libs.plugins.baselineprofile)
Expand Down Expand Up @@ -53,7 +52,7 @@ android {
// To publish on the Play store a private signing key is required, but to allow anyone
// who clones the code to sign and run the release variant, use the debug signing key.
// TODO: Abstract the signing configuration to a separate file to avoid hardcoding this.
signingConfig = signingConfigs.getByName("debug")
signingConfig = signingConfigs.named("debug").get()
// Ensure Baseline Profile is fresh for release builds.
baselineProfile.automaticGenerationDuringBuild = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import com.google.samples.apps.nowinandroid.configureJacoco
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand All @@ -23,13 +24,15 @@ import org.gradle.kotlin.dsl.getByType
class AndroidApplicationJacocoConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.gradle.jacoco")
apply("com.android.application")
pluginManager.apply("jacoco")
val androidExtension = extensions.getByType<BaseAppModuleExtension>()

androidExtension.buildTypes.configureEach {
enableAndroidTestCoverage = true
enableUnitTestCoverage = true
}
val extension = extensions.getByType<ApplicationAndroidComponentsExtension>()
configureJacoco(extension)

configureJacoco(extensions.getByType<ApplicationAndroidComponentsExtension>())
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.google.samples.apps.nowinandroid.configureJacoco
import org.gradle.api.Plugin
Expand All @@ -23,13 +25,15 @@ import org.gradle.kotlin.dsl.getByType
class AndroidLibraryJacocoConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.gradle.jacoco")
apply("com.android.library")
pluginManager.apply("jacoco")
val androidExtension = extensions.getByType<LibraryExtension>()

androidExtension.buildTypes.configureEach {
enableAndroidTestCoverage = true
enableUnitTestCoverage = true
}
val extension = extensions.getByType<LibraryAndroidComponentsExtension>()
configureJacoco(extension)

configureJacoco(extensions.getByType<LibraryAndroidComponentsExtension>())
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import androidx.room.gradle.RoomExtension
import com.google.devtools.ksp.gradle.KspExtension
import com.google.samples.apps.nowinandroid.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand All @@ -28,6 +29,10 @@ class AndroidRoomConventionPlugin : Plugin<Project> {
pluginManager.apply("androidx.room")
pluginManager.apply("com.google.devtools.ksp")

extensions.configure<KspExtension> {
arg("room.generateKotlin", "true")
}

extensions.configure<RoomExtension> {
// The schemas directory contains a schema file for each version of the Room database.
// This is required to enable Room auto migrations.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 The Android Open Source Project
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,13 @@

package com.google.samples.apps.nowinandroid

import com.android.build.api.artifact.ScopedArtifact
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.ScopedArtifacts
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.register
Expand All @@ -32,51 +37,78 @@ private val coverageExclusions = listOf(
"**/R.class",
"**/R\$*.class",
"**/BuildConfig.*",
"**/Manifest*.*"
"**/Manifest*.*",
"**/*_Hilt*.class",
"**/Hilt_*.class",
)

private fun String.capitalize() = replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}

/**
* Creates a new task that generates a combined coverage report with data from local and
* instrumented tests.
*
* `create{variant}CombinedCoverageReport`
*
* Note that coverage data must exist before running the task. This allows us to run device
* tests on CI using a different Github Action or an external device farm.
*/
internal fun Project.configureJacoco(
androidComponentsExtension: AndroidComponentsExtension<*, *, *>,
) {
configure<JacocoPluginExtension> {
toolVersion = libs.findVersion("jacoco").get().toString()
}

val jacocoTestReport = tasks.create("jacocoTestReport")

androidComponentsExtension.onVariants { variant ->
val testTaskName = "test${variant.name.capitalize()}UnitTest"
val myObjFactory = project.objects
val buildDir = layout.buildDirectory.get().asFile
val reportTask = tasks.register("jacoco${testTaskName.capitalize()}Report", JacocoReport::class) {
dependsOn(testTaskName)
val allJars: ListProperty<RegularFile> = myObjFactory.listProperty(RegularFile::class.java)
val allDirectories: ListProperty<Directory> = myObjFactory.listProperty(Directory::class.java)
val reportTask =
tasks.register("create${variant.name.capitalize()}CombinedCoverageReport", JacocoReport::class) {

reports {
xml.required.set(true)
html.required.set(true)
}

classDirectories.setFrom(
fileTree("$buildDir/tmp/kotlin-classes/${variant.name}") {
exclude(coverageExclusions)
classDirectories.setFrom(
allJars,
allDirectories.map { dirs ->
dirs.map { dir ->
myObjFactory.fileTree().setDir(dir).exclude(coverageExclusions)
}
}
)
reports {
xml.required.set(true)
html.required.set(true)
}
)

sourceDirectories.setFrom(files("$projectDir/src/main/java", "$projectDir/src/main/kotlin"))
executionData.setFrom(file("$buildDir/jacoco/$testTaskName.exec"))
}
// TODO: This is missing files in src/debug/, src/prod, src/demo, src/demoDebug...
sourceDirectories.setFrom(files("$projectDir/src/main/java", "$projectDir/src/main/kotlin"))

executionData.setFrom(
project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest")
.matching { include("**/*.exec") },

project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest")
.matching { include("**/*.ec") }
)
}


jacocoTestReport.dependsOn(reportTask)
variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT)
.use(reportTask)
.toGet(
ScopedArtifact.CLASSES,
{ _ -> allJars },
{ _ -> allDirectories },
)
}

tasks.withType<Test>().configureEach {
configure<JacocoTaskExtension> {
// Required for JaCoCo + Robolectric
// https://github.com/robolectric/robolectric/issues/2230
// TODO: Consider removing if not we don't add Robolectric
isIncludeNoLocationClasses = true

// Required for JDK 11 with the above
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 The Android Open Source Project
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,8 +14,9 @@
* limitations under the License.
*/

package com.google.samples.apps.nowinandroid.core.database
package com.google.samples.apps.nowinandroid.core.database.di

import com.google.samples.apps.nowinandroid.core.database.NiaDatabase
import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDao
import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceFtsDao
import com.google.samples.apps.nowinandroid.core.database.dao.RecentSearchQueryDao
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 The Android Open Source Project
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,10 +14,11 @@
* limitations under the License.
*/

package com.google.samples.apps.nowinandroid.core.database
package com.google.samples.apps.nowinandroid.core.database.di

import android.content.Context
import androidx.room.Room
import com.google.samples.apps.nowinandroid.core.database.NiaDatabase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand Down
Loading

0 comments on commit 0c8f105

Please sign in to comment.