Merge pull request #305 from android/sep26-merge

Sep 26th gerrit -> github merge
pull/306/head
Don Turner 2 years ago committed by GitHub
commit 46deba844e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,7 +6,7 @@ label: 'triage me'
Thank you for opening a Pull Request! Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly: Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
- [ ] Make sure to open a GitHub issue as a bug/feature request before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Make sure to open a GitHub issue as a bug/feature request before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
- [ ] Ensure the tests and linter pass (`./gradlew spotlessApply` to automatically apply formatting) - [ ] Ensure the tests and linter pass (`./gradlew --init-script gradle/init.gradle.kts spotlessApply` to automatically apply formatting)
- [ ] Appropriate docs were updated (if necessary) - [ ] Appropriate docs were updated (if necessary)
Is this your first Pull Request? Is this your first Pull Request?

@ -34,10 +34,10 @@ jobs:
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
- name: Check spotless - name: Check spotless
run: ./gradlew spotlessCheck --stacktrace run: ./gradlew spotlessCheck --init-script gradle/init.gradle.kts --no-configuration-cache --stacktrace
- name: Check lint - name: Check lint
run: ./gradlew lintDebug --stacktrace run: ./gradlew lintDemoDebug --stacktrace
- name: Build all build type and flavor permutations - name: Build all build type and flavor permutations
run: ./gradlew assemble --stacktrace run: ./gradlew assemble --stacktrace

@ -16,7 +16,6 @@
plugins { plugins {
id("nowinandroid.android.application") id("nowinandroid.android.application")
id("nowinandroid.android.application.compose") id("nowinandroid.android.application.compose")
id("nowinandroid.spotless")
} }
android { android {

@ -20,10 +20,8 @@ plugins {
id("nowinandroid.android.application") id("nowinandroid.android.application")
id("nowinandroid.android.application.compose") id("nowinandroid.android.application.compose")
id("nowinandroid.android.application.jacoco") id("nowinandroid.android.application.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("jacoco") id("jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
id("nowinandroid.firebase-perf") id("nowinandroid.firebase-perf")
} }
@ -67,19 +65,6 @@ android {
} }
} }
// @see Flavor for more details on the app product flavors.
flavorDimensions += FlavorDimension.contentType.name
productFlavors {
Flavor.values().forEach {
create(it.name) {
dimension = it.dimension.name
if (it.applicationIdSuffix != null) {
applicationIdSuffix = it.applicationIdSuffix
}
}
}
}
packagingOptions { packagingOptions {
resources { resources {
excludes.add("/META-INF/{AL2.0,LGPL2.1}") excludes.add("/META-INF/{AL2.0,LGPL2.1}")
@ -124,17 +109,13 @@ dependencies {
implementation(libs.coil.kt) implementation(libs.coil.kt)
implementation(libs.coil.kt.svg) implementation(libs.coil.kt.svg)
}
implementation(libs.hilt.android) // androidx.test is forcing JUnit, 4.12. This forces it to use 4.13
kapt(libs.hilt.compiler) configurations.configureEach {
kaptAndroidTest(libs.hilt.compiler) resolutionStrategy {
force(libs.junit4)
// androidx.test is forcing JUnit, 4.12. This forces it to use 4.13 // Temporary workaround for https://issuetracker.google.com/174733673
configurations.configureEach { force("org.objenesis:objenesis:2.6")
resolutionStrategy {
force(libs.junit4)
// Temporary workaround for https://issuetracker.google.com/174733673
force("org.objenesis:objenesis:2.6")
}
} }
} }

@ -25,7 +25,8 @@ import androidx.compose.ui.test.performClick
import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso
import androidx.test.espresso.NoActivityResumedException import androidx.test.espresso.NoActivityResumedException
import com.google.samples.apps.nowinandroid.MainActivity import com.google.samples.apps.nowinandroid.MainActivity
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.feature.foryou.R as FeatureForyouR
import com.google.samples.apps.nowinandroid.feature.interests.R as FeatureInterestsR
import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
@ -70,11 +71,11 @@ class NavigationTest {
@Before @Before
fun setup() { fun setup() {
composeTestRule.activity.apply { composeTestRule.activity.apply {
done = getString(R.string.done) done = getString(FeatureForyouR.string.done)
navigateUp = getString(R.string.navigate_up) navigateUp = getString(FeatureForyouR.string.navigate_up)
forYouLoading = getString(R.string.for_you_loading) forYouLoading = getString(FeatureForyouR.string.for_you_loading)
forYou = getString(R.string.for_you) forYou = getString(FeatureForyouR.string.for_you)
interests = getString(R.string.interests) interests = getString(FeatureInterestsR.string.interests)
sampleTopic = "Headlines" sampleTopic = "Headlines"
} }
} }

@ -19,7 +19,6 @@ import com.google.samples.apps.nowinandroid.configureFlavors
plugins { plugins {
id("nowinandroid.android.test") id("nowinandroid.android.test")
id("nowinandroid.spotless")
} }
android { android {
@ -30,6 +29,10 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
buildFeatures {
buildConfig = true
}
buildTypes { buildTypes {
// This benchmark buildType is used for benchmarking, and should function like your // This benchmark buildType is used for benchmarking, and should function like your
// release build (for example, with minification on). It's signed with a debug key // release build (for example, with minification on). It's signed with a debug key

@ -29,8 +29,6 @@ setup.
Current list of convention plugins: Current list of convention plugins:
- [`nowinandroid.spotless`](convention/src/main/kotlin/SpotlessConventionPlugin.kt):
Configures spotless.
- [`nowinandroid.android.application`](convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt), - [`nowinandroid.android.application`](convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt),
[`nowinandroid.android.library`](convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt), [`nowinandroid.android.library`](convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt),
[`nowinandroid.android.test`](convention/src/main/kotlin/AndroidTestConventionPlugin.kt): [`nowinandroid.android.test`](convention/src/main/kotlin/AndroidTestConventionPlugin.kt):

@ -28,7 +28,6 @@ java {
dependencies { dependencies {
compileOnly(libs.android.gradlePlugin) compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin) compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.spotless.gradlePlugin)
} }
gradlePlugin { gradlePlugin {
@ -65,9 +64,9 @@ gradlePlugin {
id = "nowinandroid.android.test" id = "nowinandroid.android.test"
implementationClass = "AndroidTestConventionPlugin" implementationClass = "AndroidTestConventionPlugin"
} }
register("spotless") { register("androidHilt") {
id = "nowinandroid.spotless" id = "nowinandroid.android.hilt"
implementationClass = "SpotlessConventionPlugin" implementationClass = "AndroidHiltConventionPlugin"
} }
register("firebase-perf") { register("firebase-perf") {
id = "nowinandroid.firebase-perf" id = "nowinandroid.firebase-perf"

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension import com.android.build.api.dsl.ApplicationExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose import com.google.samples.apps.nowinandroid.configureAndroidCompose
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
@ -24,7 +24,7 @@ class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {
pluginManager.apply("com.android.application") pluginManager.apply("com.android.application")
val extension = extensions.getByType<BaseAppModuleExtension>() val extension = extensions.getByType<ApplicationExtension>()
configureAndroidCompose(extension) configureAndroidCompose(extension)
} }
} }

@ -14,8 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.dsl.ApplicationExtension
import com.google.samples.apps.nowinandroid.configureFlavors
import com.google.samples.apps.nowinandroid.configureKotlinAndroid import com.google.samples.apps.nowinandroid.configureKotlinAndroid
import com.google.samples.apps.nowinandroid.configurePrintApksTask
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.configure
@ -28,9 +31,13 @@ class AndroidApplicationConventionPlugin : Plugin<Project> {
apply("org.jetbrains.kotlin.android") apply("org.jetbrains.kotlin.android")
} }
extensions.configure<BaseAppModuleExtension> { extensions.configure<ApplicationExtension> {
configureKotlinAndroid(this) configureKotlinAndroid(this)
defaultConfig.targetSdk = 33 defaultConfig.targetSdk = 33
configureFlavors(this)
}
extensions.configure<ApplicationAndroidComponentsExtension> {
configurePrintApksTask(this)
} }
} }
} }

@ -26,9 +26,8 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {
pluginManager.apply { pluginManager.apply {
apply("com.android.library") apply("nowinandroid.android.library")
apply("org.jetbrains.kotlin.android") apply("nowinandroid.android.hilt")
apply("org.jetbrains.kotlin.kapt")
} }
extensions.configure<LibraryExtension> { extensions.configure<LibraryExtension> {
defaultConfig { defaultConfig {
@ -59,9 +58,6 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
add("implementation", libs.findLibrary("kotlinx.coroutines.android").get()) add("implementation", libs.findLibrary("kotlinx.coroutines.android").get())
add("implementation", libs.findLibrary("hilt.android").get())
add("kapt", libs.findLibrary("hilt.compiler").get())
// TODO : Remove this dependency once we upgrade to Android Studio Dolphin b/228889042 // TODO : Remove this dependency once we upgrade to Android Studio Dolphin b/228889042
// These dependencies are currently necessary to render Compose previews // These dependencies are currently necessary to render Compose previews
add( add(

@ -0,0 +1,44 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.google.samples.apps.nowinandroid.configureJacoco
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.kotlin
class AndroidHiltConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.kapt")
apply("dagger.hilt.android.plugin")
}
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
"implementation"(libs.findLibrary("hilt.android").get())
"kapt"(libs.findLibrary("hilt.compiler").get())
"kaptAndroidTest"(libs.findLibrary("hilt.compiler").get())
}
}
}
}

@ -14,9 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.LibraryExtension import com.android.build.gradle.LibraryExtension
import com.google.samples.apps.nowinandroid.configureFlavors import com.google.samples.apps.nowinandroid.configureFlavors
import com.google.samples.apps.nowinandroid.configureKotlinAndroid import com.google.samples.apps.nowinandroid.configureKotlinAndroid
import com.google.samples.apps.nowinandroid.configurePrintApksTask
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.artifacts.VersionCatalogsExtension
@ -37,18 +40,17 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
defaultConfig.targetSdk = 33 defaultConfig.targetSdk = 33
configureFlavors(this) configureFlavors(this)
} }
extensions.configure<LibraryAndroidComponentsExtension> {
configurePrintApksTask(this)
}
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies { configurations.configureEach {
configurations.configureEach { resolutionStrategy {
resolutionStrategy { force(libs.findLibrary("junit4").get())
force(libs.findLibrary("junit4").get()) // Temporary workaround for https://issuetracker.google.com/174733673
// Temporary workaround for https://issuetracker.google.com/174733673 force("org.objenesis:objenesis:2.6")
force("org.objenesis:objenesis:2.6")
}
} }
} }
} }
} }
}
}

@ -1,53 +0,0 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.getByType
class SpotlessConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.diffplug.spotless")
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
extensions.configure<SpotlessExtension> {
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
ktlint(libs.findVersion("ktlint").get().toString()).userData(mapOf("android" to "true"))
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
}
format("kts") {
target("**/*.kts")
targetExclude("**/build/**/*.kts")
// Look for the first line that doesn't have a block comment (assumed to be the license)
licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
}
format("xml") {
target("**/*.xml")
targetExclude("**/build/**/*.xml")
// Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml)
licenseHeaderFile(rootProject.file("spotless/copyright.xml"), "(<[^!?])")
}
}
}
}
}

@ -1,5 +1,8 @@
package com.google.samples.apps.nowinandroid package com.google.samples.apps.nowinandroid
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ApplicationProductFlavor
import com.android.build.api.dsl.ApplicationVariantDimension
import com.android.build.api.dsl.CommonExtension import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project import org.gradle.api.Project
@ -24,6 +27,11 @@ fun Project.configureFlavors(
Flavor.values().forEach{ Flavor.values().forEach{
create(it.name) { create(it.name) {
dimension = it.dimension.name dimension = it.dimension.name
if (this@apply is ApplicationExtension && this is ApplicationProductFlavor) {
if (it.applicationIdSuffix != null) {
this.applicationIdSuffix = it.applicationIdSuffix
}
}
} }
} }
} }

@ -0,0 +1,98 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.BuiltArtifactsLoader
import com.android.build.api.variant.HasAndroidTest
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import java.io.File
internal fun Project.configurePrintApksTask(extension: AndroidComponentsExtension<*, *, *>) {
extension.onVariants { variant ->
if (variant is HasAndroidTest) {
val loader = variant.artifacts.getBuiltArtifactsLoader()
val artifact = variant.androidTest?.artifacts?.get(SingleArtifact.APK)
val javaSources = variant.androidTest?.sources?.java?.all
val kotlinSources = variant.androidTest?.sources?.kotlin?.all
val testSources = if (javaSources != null && kotlinSources != null) {
javaSources.zip(kotlinSources) { javaDirs, kotlinDirs ->
javaDirs + kotlinDirs
}
} else javaSources ?: kotlinSources
if (artifact != null && testSources != null) {
tasks.register(
"${variant.name}PrintTestApk",
PrintApkLocationTask::class.java
) {
apkFolder.set(artifact)
builtArtifactsLoader.set(loader)
variantName.set(variant.name)
sources.set(testSources)
}
}
}
}
}
internal abstract class PrintApkLocationTask : DefaultTask() {
@get:InputDirectory
abstract val apkFolder: DirectoryProperty
@get:InputFiles
abstract val sources: ListProperty<Directory>
@get:Internal
abstract val builtArtifactsLoader: Property<BuiltArtifactsLoader>
@get:Input
abstract val variantName: Property<String>
@TaskAction
fun taskAction() {
val hasFiles = sources.orNull?.any { directory ->
directory.asFileTree.files.any {
it.isFile && it.parentFile.path.contains("build${File.separator}generated").not()
}
} ?: throw RuntimeException("Cannot check androidTest sources")
// Don't print APK location if there are no androidTest source files
if (!hasFiles) {
return
}
val builtArtifacts = builtArtifactsLoader.get().load(apkFolder.get())
?: throw RuntimeException("Cannot load APKs")
if (builtArtifacts.elements.size != 1)
throw RuntimeException("Expected one APK !")
val apk = File(builtArtifacts.elements.single().outputFile).toPath()
println(apk)
}
}

@ -28,4 +28,5 @@ dependencyResolutionManagement {
} }
} }
rootProject.name = "build-logic"
include(":convention") include(":convention")

@ -31,5 +31,4 @@ plugins {
alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.hilt) apply false alias(libs.plugins.hilt) apply false
alias(libs.plugins.secrets) apply false alias(libs.plugins.secrets) apply false
alias(libs.plugins.spotless) apply false
} }

@ -16,14 +16,10 @@
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.coroutines.android)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
testImplementation(project(":core:testing")) testImplementation(project(":core:testing"))
} }

@ -15,16 +15,10 @@
*/ */
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
api(project(":core:data")) api(project(":core:data"))
implementation(project(":core:testing")) implementation(project(":core:testing"))
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
kaptAndroidTest(libs.hilt.compiler)
} }

@ -16,10 +16,8 @@
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("kotlinx-serialization") id("kotlinx-serialization")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
@ -35,7 +33,4 @@ dependencies {
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
} }

@ -18,10 +18,8 @@
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
alias(libs.plugins.ksp) alias(libs.plugins.ksp)
id("nowinandroid.spotless")
} }
android { android {
@ -47,8 +45,5 @@ dependencies {
implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
androidTestImplementation(project(":core:testing")) androidTestImplementation(project(":core:testing"))
} }

@ -15,9 +15,7 @@
*/ */
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
@ -25,8 +23,4 @@ dependencies {
implementation(project(":core:testing")) implementation(project(":core:testing"))
api(libs.androidx.dataStore.core) api(libs.androidx.dataStore.core)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
kaptAndroidTest(libs.hilt.compiler)
} }

@ -24,10 +24,8 @@ import com.google.protobuf.gradle.protoc
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
alias(libs.plugins.protobuf) alias(libs.plugins.protobuf)
id("nowinandroid.spotless")
} }
android { android {
@ -65,10 +63,6 @@ dependencies {
implementation(libs.androidx.dataStore.core) implementation(libs.androidx.dataStore.core)
implementation(libs.protobuf.kotlin.lite) implementation(libs.protobuf.kotlin.lite)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
kaptAndroidTest(libs.hilt.compiler)
} }
// TODO b/239411851, Remove kapt workaround configuration // TODO b/239411851, Remove kapt workaround configuration

@ -17,7 +17,6 @@ plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("nowinandroid.spotless")
} }
android { android {

@ -17,7 +17,6 @@
@Suppress("DSL_SCOPE_VIOLATION") @Suppress("DSL_SCOPE_VIOLATION")
plugins { plugins {
id("kotlin") id("kotlin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {

@ -18,16 +18,10 @@
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
alias(libs.plugins.ksp)
id("nowinandroid.spotless")
} }
dependencies { dependencies {
api(libs.androidx.hilt.navigation.compose) api(libs.androidx.hilt.navigation.compose)
api(libs.androidx.navigation.compose) api(libs.androidx.navigation.compose)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
} }

@ -13,16 +13,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("kotlinx-serialization") id("kotlinx-serialization")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
} }
android {
buildFeatures {
buildConfig = true
}
}
secrets { secrets {
defaultPropertiesFileName = "secrets.defaults.properties" defaultPropertiesFileName = "secrets.defaults.properties"
} }
@ -40,7 +45,4 @@ dependencies {
implementation(libs.okhttp.logging) implementation(libs.okhttp.logging)
implementation(libs.retrofit.core) implementation(libs.retrofit.core)
implementation(libs.retrofit.kotlin.serialization) implementation(libs.retrofit.kotlin.serialization)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
} }

@ -15,8 +15,7 @@
*/ */
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
kotlin("kapt") id("nowinandroid.android.hilt")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
@ -24,9 +23,6 @@ dependencies {
implementation(project(":core:data")) implementation(project(":core:data"))
implementation(project(":core:model")) implementation(project(":core:model"))
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
api(libs.junit4) api(libs.junit4)
api(libs.androidx.test.core) api(libs.androidx.test.core)
api(libs.kotlinx.coroutines.test) api(libs.kotlinx.coroutines.test)

@ -17,7 +17,6 @@ plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
@ -47,4 +46,4 @@ dependencies {
api(libs.androidx.compose.runtime.livedata) api(libs.androidx.compose.runtime.livedata)
api(libs.androidx.metrics) api(libs.androidx.metrics)
api(libs.androidx.tracing.ktx) api(libs.androidx.tracing.ktx)
} }

@ -57,6 +57,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.google.samples.apps.nowinandroid.core.designsystem.R as DesignsystemR
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
@ -135,7 +136,7 @@ fun NewsResourceHeaderImage(
) { ) {
AsyncImage( AsyncImage(
placeholder = if (LocalInspectionMode.current) { placeholder = if (LocalInspectionMode.current) {
painterResource(R.drawable.ic_placeholder_default) painterResource(DesignsystemR.drawable.ic_placeholder_default)
} else { } else {
// TODO b/228077205, show specific loading image visual // TODO b/228077205, show specific loading image visual
null null

@ -14,12 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library")
id("nowinandroid.android.feature") id("nowinandroid.android.feature")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {

@ -209,7 +209,9 @@ private fun AuthorToolbar(
IconButton(onClick = { onBackClick() }) { IconButton(onClick = { onBackClick() }) {
Icon( Icon(
imageVector = Filled.ArrowBack, imageVector = Filled.ArrowBack,
contentDescription = stringResource(id = R.string.back) contentDescription = stringResource(
id = com.google.samples.apps.nowinandroid.core.ui.R.string.back
)
) )
} }
val selected = uiState.isFollowed val selected = uiState.isFollowed

@ -14,12 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library")
id("nowinandroid.android.feature") id("nowinandroid.android.feature")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {

@ -14,12 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library")
id("nowinandroid.android.feature") id("nowinandroid.android.feature")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {

@ -14,10 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library")
id("nowinandroid.android.feature") id("nowinandroid.android.feature")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }

@ -14,14 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
plugins { plugins {
id("nowinandroid.android.library")
id("nowinandroid.android.feature") id("nowinandroid.android.feature")
id("nowinandroid.android.library.compose") id("nowinandroid.android.library.compose")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
dependencies { dependencies {
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
} }

@ -211,7 +211,9 @@ private fun TopicToolbar(
IconButton(onClick = { onBackClick() }) { IconButton(onClick = { onBackClick() }) {
Icon( Icon(
imageVector = Filled.ArrowBack, imageVector = Filled.ArrowBack,
contentDescription = stringResource(id = R.string.back) contentDescription = stringResource(
id = com.google.samples.apps.nowinandroid.core.ui.R.string.back
)
) )
} }
val selected = uiState.isFollowed val selected = uiState.isFollowed

@ -4,17 +4,26 @@
# any settings specified in this file. # any settings specified in this file.
# For more details on how to configure your build environment visit # For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
org.gradle.configureondemand=true
org.gradle.caching=true
org.gradle.parallel=true
# Ensure important default jvmargs aren't overwritten. See https://github.com/gradle/gradle/issues/19750 # Ensure important default jvmargs aren't overwritten. See https://github.com/gradle/gradle/issues/19750
org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true org.gradle.parallel=true
# Not encouraged by Gradle and can produce weird results. Wait for isolated projects instead.
org.gradle.configureondemand=false
# Enable caching between builds.
org.gradle.caching=true
# Enable configuration caching between builds.
org.gradle.unsafe.configuration-cache=true
# AndroidX package structure to make it clearer which packages are bundled with the # 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 # Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
@ -23,3 +32,14 @@ android.useAndroidX=true
kotlin.code.style=official kotlin.code.style=official
# Allow kapt to use incremental processing # Allow kapt to use incremental processing
kapt.incremental.apt=true kapt.incremental.apt=true
# Non-transitive R classes is recommended and is faster/smaller
android.nonTransitiveRClass=true
# Disable build features that are enabled by default,
# https://developer.android.com/studio/releases/gradle-plugin#buildFeatures
android.defaults.buildfeatures.buildconfig=false
android.defaults.buildfeatures.aidl=false
android.defaults.buildfeatures.renderscript=false
android.defaults.buildfeatures.resvalues=false
android.defaults.buildfeatures.shaders=false

@ -0,0 +1,56 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
val ktlintVersion = "0.43.0"
initscript {
val spotlessVersion = "6.7.2"
repositories {
mavenCentral()
}
dependencies {
classpath("com.diffplug.spotless:spotless-plugin-gradle:$spotlessVersion")
}
}
allprojects {
if (this == rootProject) {
return@allprojects
}
apply<com.diffplug.gradle.spotless.SpotlessPlugin>()
extensions.configure<com.diffplug.gradle.spotless.SpotlessExtension> {
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
ktlint(ktlintVersion).userData(mapOf("android" to "true"))
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
}
format("kts") {
target("**/*.kts")
targetExclude("**/build/**/*.kts")
// Look for the first line that doesn't have a block comment (assumed to be the license)
licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
}
format("xml") {
target("**/*.xml")
targetExclude("**/build/**/*.xml")
// Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml)
licenseHeaderFile(rootProject.file("spotless/copyright.xml"), "(<[^!?])")
}
}
}

@ -39,7 +39,6 @@ kotlinxCoroutines = "1.6.4"
kotlinxDatetime = "0.4.0" kotlinxDatetime = "0.4.0"
kotlinxSerializationJson = "1.4.0" kotlinxSerializationJson = "1.4.0"
ksp = "1.7.10-1.0.6" ksp = "1.7.10-1.0.6"
ktlint = "0.43.0"
lint = "30.2.2" lint = "30.2.2"
okhttp = "4.10.0" okhttp = "4.10.0"
protobuf = "3.21.5" protobuf = "3.21.5"
@ -48,7 +47,6 @@ retrofit = "2.9.0"
retrofitKotlinxSerializationJson = "0.8.0" retrofitKotlinxSerializationJson = "0.8.0"
room = "2.4.3" room = "2.4.3"
secrets = "2.0.1" secrets = "2.0.1"
spotless = "6.7.2"
turbine = "0.8.0" turbine = "0.8.0"
[libraries] [libraries]
@ -122,7 +120,6 @@ room-compiler = { group = "androidx.room", name = "room-compiler", version.ref =
# Dependencies of the included build-logic # Dependencies of the included build-logic
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
spotless-gradlePlugin = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotless" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
@ -133,5 +130,4 @@ hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" } secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }

@ -58,12 +58,12 @@ run_firebase_test_lab() {
set +e # To not exit on an error to retry flaky tests set +e # To not exit on an error to retry flaky tests
local counter=0 local counter=0
local result=1 local result=1
local module=$1 local testApk=$1
while [ $result != 0 -a $counter -lt $MAX_RETRY ]; do while [ $result != 0 -a $counter -lt $MAX_RETRY ]; do
gcloud firebase test android run \ gcloud firebase test android run \
--type instrumentation \ --type instrumentation \
--app "app/build/outputs/apk/demo/debug/app-demo-debug.apk" \ --app "app/build/outputs/apk/demo/debug/app-demo-debug.apk" \
--test "$module/build/outputs/apk/androidTest/demo/debug/$module-demo-debug-androidTest.apk" \ --test "$testApk" \
--device-ids $deviceIds \ --device-ids $deviceIds \
--os-version-ids $osVersionIds \ --os-version-ids $osVersionIds \
--locales en \ --locales en \
@ -76,17 +76,14 @@ run_firebase_test_lab() {
# All modules with androidTest to run tests on. # All modules with androidTest to run tests on.
# This command will create a list like ["app", "sync"] based on which subdirectories testApks=($(./gradlew -q demoDebugPrintTestApk))
# (assumed to be modules) have an androidTest source directory.
# The sed regex pulls out the module name from the matched directory
modules=($(find . -regex ".*/src/androidTest" | sed -E 's|\./([^/]*)/.*|\1|g'))
# Run all modules in parallel with Firebase Test Lab, and fail if any fail # Run all modules in parallel with Firebase Test Lab, and fail if any fail
pids="" pids=""
result=0 result=0
for module in ${modules[@]}; do for testApk in ${testApks[@]}; do
run_firebase_test_lab $module & run_firebase_test_lab $testApk &
pids="$pids $!" pids="$pids $!"
done done

@ -64,8 +64,8 @@ class DesignSystemDetector : Detector(), Detector.UastScanner {
id = "DesignSystem", id = "DesignSystem",
briefDescription = "Design system", briefDescription = "Design system",
explanation = "This check highlights calls in code that use Compose Material " + explanation = "This check highlights calls in code that use Compose Material " +
"composables instead of equivalents from the Now in Android design system " + "composables instead of equivalents from the Now in Android design system " +
"module.", "module.",
category = Category.CUSTOM_LINT_CHECKS, category = Category.CUSTOM_LINT_CHECKS,
priority = 7, priority = 7,
severity = Severity.ERROR, severity = Severity.ERROR,

@ -62,3 +62,17 @@ include(":feature:bookmarks")
include(":feature:topic") include(":feature:topic")
include(":lint") include(":lint")
include(":sync") include(":sync")
val prePushHook = file(".git/hooks/pre-push")
val commitMsgHook = file(".git/hooks/commit-msg")
val hooksInstalled = commitMsgHook.exists()
&& prePushHook.exists()
&& prePushHook.readBytes().contentEquals(file("tools/pre-push").readBytes())
if (!hooksInstalled) {
exec {
commandLine("tools/setup.sh")
workingDir = rootProject.projectDir
}
}

@ -16,9 +16,7 @@
plugins { plugins {
id("nowinandroid.android.library") id("nowinandroid.android.library")
id("nowinandroid.android.library.jacoco") id("nowinandroid.android.library.jacoco")
kotlin("kapt") id("nowinandroid.android.hilt")
id("dagger.hilt.android.plugin")
id("nowinandroid.spotless")
} }
android { android {
@ -43,12 +41,7 @@ dependencies {
testImplementation(project(":core:testing")) testImplementation(project(":core:testing"))
androidTestImplementation(project(":core:testing")) androidTestImplementation(project(":core:testing"))
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
kapt(libs.hilt.ext.compiler) kapt(libs.hilt.ext.compiler)
androidTestImplementation(libs.androidx.work.testing) androidTestImplementation(libs.androidx.work.testing)
kaptAndroidTest(libs.hilt.compiler)
kaptAndroidTest(libs.hilt.ext.compiler)
} }

@ -69,7 +69,9 @@ private fun Context.syncWorkNotification(): Notification {
this, this,
SyncNotificationChannelID SyncNotificationChannelID
) )
.setSmallIcon(R.drawable.ic_nia_notification) .setSmallIcon(
com.google.samples.apps.nowinandroid.core.common.R.drawable.ic_nia_notification
)
.setContentTitle(getString(R.string.sync_notification_title)) .setContentTitle(getString(R.string.sync_notification_title))
.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build() .build()

@ -88,7 +88,7 @@ done
if [[ -n "$run_checks" ]]; then if [[ -n "$run_checks" ]]; then
# pre-push usually executes in the repository root, but just to be safe... # pre-push usually executes in the repository root, but just to be safe...
cd "$(git rev-parse --show-toplevel)" cd "$(git rev-parse --show-toplevel)"
./gradlew check ./gradlew --init-script gradle/init.gradle.kts --no-configuration-cache check
exit $? exit $?
fi fi

Loading…
Cancel
Save