Skip to content

Commit

Permalink
Add Convention Plugins for Android
Browse files Browse the repository at this point in the history
  • Loading branch information
jjohannes committed Sep 2, 2024
1 parent f0dabd8 commit 170b6b5
Show file tree
Hide file tree
Showing 23 changed files with 176 additions and 148 deletions.
19 changes: 0 additions & 19 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,5 @@ jobs:
with:
cache-read-only: false
- run: "./gradlew qualityCheck"
- run: "./gradlew test"
- run: "./gradlew testEndToEnd"
- run: "./gradlew testEndToEndSlow"
- run: "./gradlew check"
- run: "./gradlew cyclonedxBom --no-configuration-cache"
- run: "./gradlew publish"
if: ${{ !contains(github.ref_name, '/') }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: reports
path: gradle/aggregation/build/reports
- uses: DependencyTrack/gh-upload-sbom@v3
if: ${{ !contains(github.ref_name, '/') }}
with:
apiKey: ${{ secrets.DEPENDENCYTRACK_APIKEY }}
bomFilename: "gradle/aggregation/build/reports/sbom/bom.xml"
serverHostname: ${{ secrets.DEPENDENCYTRACK_URL }}
projectName: "gradle-project-setup-howto"
projectVersion: ${{ github.ref_name }}
autoCreate: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.gradle
.idea
build
local.properties
14 changes: 5 additions & 9 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
plugins { id("org.example.gradle.component.application") }

application { mainClass = "org.example.product.app.Application" }

// Complicated notation for 'capabilities' - upvote: https://github.com/gradle/gradle/issues/25629
dependencies {
implementation(projects.bespin)
Expand All @@ -10,18 +8,16 @@ dependencies {
implementation(projects.kashyyyk)
implementation(projects.naboo)
implementation(projects.tatooine)
implementation(libs.android.material)
implementation(libs.androidx.appcompat)
implementation(libs.guice)
implementation(libs.guice.servlet)
implementation(libs.slf4j.api)
runtimeOnly(libs.slf4j.simple)
providedCompile(libs.jakarta.servlet.api)

mockApiImplementation(projects.app)
mockApiImplementation(libs.guava)
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.monitor)
androidTestImplementation(libs.junit4)

testImplementation(libs.junit.jupiter.api)

testEndToEndImplementation(projects.app) { capabilities { requireCapability("${project.group}:$name-mock-api") } }
testEndToEndImplementation(libs.guava)
testEndToEndImplementation(libs.junit.jupiter.api)
}
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ org.gradle.configuration-cache=true

# activate Gradle build cache - switch between branches/commits without rebuilding every time
org.gradle.caching=true

android.useAndroidX=true
40 changes: 38 additions & 2 deletions gradle/aggregation/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import com.android.build.api.attributes.BuildTypeAttr

plugins {
id("org.gradle.java")
id("org.example.gradle.base.lifecycle")
id("org.example.gradle.base.dependency-rules")
id("org.example.gradle.check.format-gradle")
id("org.example.gradle.report.code-coverage")
// id("org.example.gradle.report.code-coverage")
id("org.example.gradle.report.plugin-analysis")
id("org.example.gradle.report.sbom")
id("org.example.gradle.report.test")
// id("org.example.gradle.report.test")
}

dependencies { implementation(projects.app) }

configurations {
compileClasspath { selectRelease() }
runtimeClasspath { selectRelease() }
testCompileClasspath { selectRelease() }
testRuntimeClasspath { selectRelease() }
}

fun Configuration.selectRelease() {
attributes.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, "jar")
attributes.attribute(BuildTypeAttr.ATTRIBUTE, objects.named("release"))
}

// Allow AARs to appear along JARs on the joint classpath for reports
dependencies {
attributesSchema { getMatchingStrategy(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE).compatibilityRules.add(AarJarCompatibility::class.java) }
attributesSchema { getMatchingStrategy(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE).compatibilityRules.add(AarJarStringCompatibility::class.java) }
}

class AarJarCompatibility : AttributeCompatibilityRule<LibraryElements> {
override fun execute(details: CompatibilityCheckDetails<LibraryElements>) {
if (details.producerValue?.name == "aar") {
details.compatible()
}
}
}

class AarJarStringCompatibility : AttributeCompatibilityRule<String> {
override fun execute(details: CompatibilityCheckDetails<String>) {
if (details.producerValue == "aar" || details.producerValue == "android-classes-jar") {
details.compatible()
}
}
}
10 changes: 10 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
[versions]
android-material = "1.12.0"
androidx-appcompat = "1.7.0"
androidx-test = "1.1.5"
assertj = "3.22.0"
espresso = "3.5.1"
guava = "30.1-jre"
guice = "5.1.0"
httpcomponents = "4.5.13"
Expand All @@ -22,6 +26,11 @@ velocity = "2.3"
zookeeper = "3.8.0"

[libraries]
android-material = { module = "com.google.android.material:material", version.ref = "android-material" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso"}
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test" }
androidx-test-monitor = { module = "androidx.test:monitor" }
assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
commons-io = { module = "commons-io:commons-io" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
Expand All @@ -39,6 +48,7 @@ jakarta-mail-impl = { module = "com.sun.mail:jakarta.mail", version.ref = "jakar
jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta-servlet" }
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit5" }
junit4 = { module = "junit:junit" }
opensaml = { module = "org.opensaml:opensaml", version.ref = "opensaml" }
org-json = { module = "org.json:json", version.ref = "org-json" }
org-reflections = { module = "org.reflections:reflections", version.ref = "org-reflections" }
Expand Down
6 changes: 5 additions & 1 deletion gradle/plugins/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
plugins { `kotlin-dsl` }

repositories { gradlePluginPortal() }
repositories {
gradlePluginPortal()
google()
}

dependencies {
implementation("com.android.tools.build:gradle:8.3.0")
implementation("com.autonomousapps:dependency-analysis-gradle-plugin:2.0.1")
implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0")
implementation("com.gradle:develocity-gradle-plugin:3.18")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ jvmDependencyConflicts {
logging { enforceSlf4JSimple() }

patch {
// Avoid conflict between 'javax.activation' and 'jakarta.activation-api' in the
// detachedConfiguration that is input to AndroidLintTask.lintTool.classpath
// Because for 'detachedConfigurations' you cannot inject conflict resolution strategies
// select(JAVAX_ACTIVATION_API, "jakarta.activation:jakarta.activation-api")
// would not solve the issue.
module("com.android.tools:repository") {
removeDependency("com.sun.activation:javax.activation")
addApiDependency("jakarta.activation:jakarta.activation-api")
}

module("com.github.racc:typesafeconfig-guice") {
// remove and re-add due to 'no_aop' classifier
removeDependency("com.google.inject:guice")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins { id("org.gradle.base") }

// Set the group required to refer to a Module "from outside".
// I.e., when it is published or used in Included Builds.
group = "org.example.product.java"
group = "org.example.product.android"

// Set the version from 'version.txt'
version = providers.fileContents(isolated.rootProject.projectDirectory.file("gradle/version.txt")).asText.getOrElse("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import com.autonomousapps.DependencyAnalysisSubExtension
import com.autonomousapps.tasks.ProjectHealthTask

plugins {
id("org.gradle.java")
id("org.gradle.java-base")
id("com.autonomousapps.dependency-analysis")
id("io.fuchs.gradle.classpath-collision-detector")
id("org.example.gradle.base.lifecycle")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
id("org.example.gradle.base.dependency-rules")
id("org.example.gradle.base.identity")
id("org.example.gradle.base.lifecycle")
id("org.example.gradle.check.dependencies")
id("org.example.gradle.check.format-gradle")
id("org.example.gradle.check.format-java")
id("org.example.gradle.feature.android-library")
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
plugins {
id("org.gradle.application")
id("org.example.gradle.base.dependency-rules")
id("org.example.gradle.base.identity")
id("org.example.gradle.base.lifecycle")
id("org.example.gradle.check.dependencies")
id("org.example.gradle.check.format-gradle")
id("org.example.gradle.check.format-java")
id("org.example.gradle.feature.android-application")
id("org.example.gradle.feature.checksum")
id("org.example.gradle.feature.compile-java")
id("org.example.gradle.feature.javadoc")
id("org.example.gradle.feature.test")
id("org.example.gradle.feature.test-end-to-end")
id("org.example.gradle.feature.war")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
plugins {
id("org.example.gradle.base.lifecycle")
id("org.example.gradle.base.dependency-rules")
id("com.android.application")
}

val versionString =
providers.fileContents(isolated.rootProject.projectDirectory.file("gradle/version.txt")).asText.getOrElse("")
val versionInt = versionString.split(".")[0].toInt() * 1000 + versionString.split(".")[1].toInt()

android {
compileSdk = 34
namespace = "org.example.product.${project.name}"
defaultConfig {
applicationId = "org.example.product.app"
minSdk = 26
targetSdk = 34
versionCode = versionInt
versionName = versionString

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes.getByName("release") { minifyEnabled(false) }

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

packaging { resources.excludes.add("META-INF/**") }
}

// Configure common test runtime dependencies for android application projects
dependencies { androidTestRuntimeOnly("androidx.test.espresso:espresso-core") }

// Required, because 'org.gradlex.jvm-dependency-conflict-resolution' does not
// automatically configure everything for Android (yet)
android {
applicationVariants.all {
compileConfiguration.configureConsistentResolution()
runtimeConfiguration.configureConsistentResolution()
unitTestVariant.compileConfiguration.configureConsistentResolution()
unitTestVariant.runtimeConfiguration.configureConsistentResolution()
if (testVariant != null) {
testVariant.compileConfiguration.configureConsistentResolution()
testVariant.runtimeConfiguration.configureConsistentResolution()
}
}
}

fun Configuration.configureConsistentResolution() {
extendsFrom(configurations["internal"])
shouldResolveConsistentlyWith(configurations["mainRuntimeClasspath"])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
plugins {
id("org.example.gradle.base.lifecycle")
id("org.example.gradle.base.dependency-rules")
id("com.android.library")
}

android {
compileSdk = 34
namespace = "org.example.product.${project.name}"

defaultConfig { minSdk = 26 }
}

// Required, because 'org.gradlex.jvm-dependency-conflict-resolution' does not
// automatically configure everything for Android (yet)
android {
libraryVariants.all {
compileConfiguration.configureConsistentResolution()
runtimeConfiguration.configureConsistentResolution()
unitTestVariant.compileConfiguration.configureConsistentResolution()
unitTestVariant.runtimeConfiguration.configureConsistentResolution()
if (testVariant != null) {
testVariant.compileConfiguration.configureConsistentResolution()
testVariant.runtimeConfiguration.configureConsistentResolution()
}
}
packaging { resources.excludes.add("META-INF/*") }
}

fun Configuration.configureConsistentResolution() {
extendsFrom(configurations["internal"])
shouldResolveConsistentlyWith(configurations["mainRuntimeClasspath"])
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import org.example.gradle.tasks.MD5DirectoryChecksum

plugins { id("org.gradle.java") }

// Generate additional resources required at application runtime
// This is an example for creating and integrating a custom task implementation.
tasks.register<MD5DirectoryChecksum>("resourcesChecksum") {
inputDirectory = layout.projectDirectory.dir("src/main/resources")
checksumFile = layout.buildDirectory.file("generated-resources/md5/resources.MD5")
}

tasks.processResources { from(tasks.named("resourcesChecksum")) }
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
dependencyResolutionManagement {
// Get components from Maven Central
repositories.mavenCentral()
repositories.google()
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 170b6b5

Please sign in to comment.