Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Build Shrugged

The Build Shrugged

“If you saw the build system of your project, if you saw that he struggles with the build times, resources and productivity of your team, and the greater his effort the heavier the build - What would you tell him?"

I…don't know. What…could he do? What would you tell him?" “To build.”

Indeed, we can’t build our projects without build systems. It’s fundamental to understand the internals and how we can get benefits in our project. During this session we will learn the internals and what’s the current state in the Android world using Gradle. Gradle has brought very interesting concepts in the last years like Lazy configurations and Workers API. We will learn what is the impact of these features and how to apply these tools in our projects. Finally, we will learn some techniques to measure performance in our projects with Tracer Agent and different tools in the ecosystem.

Iñaki Villar

July 13, 2019
Tweet

More Decks by Iñaki Villar

Other Decks in Programming

Transcript

  1. GRADLE GRADLE ANDROID GRADLE PLUGIN android { compileSdkVersion(28) defaultConfig {

    applicationId = "com.kotlin.client" minSdkVersion(21) targetSdkVersion(28) versionCode = 1 versionName = "1.0" } }
  2. GRADLE GRADLE ANDROID GRADLE PLUGIN generatePureSplits jacoco lintOptions ndkDirectory packagingOptions

    productFlavors resourcePrefix sdkDirectory signingConfigs sourceSets splits testOptions variantFilter aaptOptions adbExecutable adbOptions buildToolsVersion buildTypes compileOptions compileSdkVersion dataBinding defaultConfig defaultPublishConfig dexOptions externalNativeBuild flavorDimensionList
  3. GRADLE GRADLE ANDROID GRADLE PLUGIN generatePureSplits jacoco lintOptions ndkDirectory packagingOptions

    productFlavors resourcePrefix sdkDirectory signingConfigs sourceSets splits testOptions variantFilter aaptOptions adbExecutable adbOptions buildToolsVersion buildTypes compileOptions compileSdkVersion dataBinding defaultConfig defaultPublishConfig dexOptions externalNativeBuild flavorDimensionList
  4. GRADLE GRADLE ANDROID GRADLE PLUGIN CUSTOM BUILD SCRIPT/PLUGINS plugins {

    id("kotlin-android") id("kotlin-android-extensions") id("kotlin-kapt") id("androidx.benchmark") }
  5. INITIALIZATION CONFIGURATION EXECUTION include ':app', ':bypass' include ':about', ':core', ':dribbble',

    ':designernews', ':search' include ':test_shared' project(':bypass').projectDir = new File(rootDir, 'third_party/bypass')
  6. INITIALIZATION CONFIGURATION EXECUTION include ':app', ':bypass' include ':about', ':core', ':dribbble',

    ':designernews', ':search' include ':test_shared' project(':bypass').projectDir = new File(rootDir, 'third_party/bypass')
  7. INITIALIZATION CONFIGURATION EXECUTION include ':app', ':bypass' include ':about', ':core', ':dribbble',

    ':designernews', ':search' include ':test_shared' project(':bypass').projectDir = new File(rootDir, 'third_party/bypass')
  8. apply plugin: 'com.android.dynamic-feature' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply

    from: '../core_dependencies.gradle' apply from: '../test_dependencies.gradle' apply from: '../repositories.gradle' android { compileSdkVersion versions.compileSdk defaultConfig { minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } dataBinding { enabled true }
  9. `when`("OutputPublisher is included") { val project = ProjectBuilder.builder().build() val talaiotExtension

    = project.extensions.create("ext", Extension::class.java, project) talaiotExtension.publishers { outputPublisher { } } val publishers = PublishersProvider(project, logger).get() then("instance of OutputPublisher is created") { publishers.forAtLeastOne { it is OutputPublisher } } } ProjectBuilder
  10. ProjectBuilder `when`("OutputPublisher is included") { val project = ProjectBuilder.builder().build() val

    talaiotExtension = project.extensions.create("talaiot", TalaiotExtension::class.java, project) talaiotExtension.publishers { outputPublisher { } } val publishers = PublishersProvider(project, logger).get() then("instance of OutputPublisher is created") { publishers.forAtLeastOne { it is OutputPublisher } } }
  11. `when`("OutputPublisher is included") { val project = ProjectBuilder.builder().build() val talaiotExtension

    = project.extensions.create("ext", Extension::class.java, project) talaiotExtension.publishers { outputPublisher { } } val publishers = PublishersProvider(project, logger).get() then("instance of OutputPublisher is created") { publishers.forAtLeastOne { it is OutputPublisher } } } ProjectBuilder
  12. `when`("OutputPublisher is included") { val project = ProjectBuilder.builder().build() val talaiotExtension

    = project.extensions.create("ext", Extension::class.java, project) talaiotExtension.publishers { outputPublisher { } } val publishers = PublishersProvider(project, logger).get() then("instance of OutputPublisher is created") { publishers.forAtLeastOne { it is OutputPublisher } } } ProjectBuilder
  13. Gradle TestKit @Test public void testHelloWorldTask() throws IOException { settingsFile

    = testProjectDir.newFile("settings.gradle"); buildFile = testProjectDir.newFile("build.gradle"); writeFile(settingsFile, "rootProject.name = 'hello-world'"); String buildFileContent = "task helloWorld {" + " doLast {" + " println 'Hello world!'" + " }" + "}"; writeFile(buildFile, buildFileContent); BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("helloWorld") .build(); assertTrue(result.getOutput().contains("Hello world!")); assertEquals(SUCCESS, result.task(":helloWorld").getOutcome()); }
  14. Gradle TestKit @Test public void testHelloWorldTask() throws IOException { settingsFile

    = testProjectDir.newFile("settings.gradle"); buildFile = testProjectDir.newFile("build.gradle"); writeFile(settingsFile, "rootProject.name = 'hello-world'"); String buildFileContent = "task helloWorld {" + " doLast {" + " println 'Hello world!'" + " }" + "}"; writeFile(buildFile, buildFileContent); BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("helloWorld") .build(); assertTrue(result.getOutput().contains("Hello world!")); assertEquals(SUCCESS, result.task(":helloWorld").getOutcome()); }
  15. Gradle TestKit @Test public void testHelloWorldTask() throws IOException { settingsFile

    = testProjectDir.newFile("settings.gradle"); buildFile = testProjectDir.newFile("build.gradle"); writeFile(settingsFile, "rootProject.name = 'hello-world'"); String buildFileContent = "task helloWorld {" + " doLast {" + " println 'Hello world!'" + " }" + "}"; writeFile(buildFile, buildFileContent); BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("helloWorld") .build(); assertTrue(result.getOutput().contains("Hello world!")); assertEquals(SUCCESS, result.task(":helloWorld").getOutcome()); }
  16. Gradle TestKit > GradleRunner GRADLE VERSION GRADLE INSTALLATION PROJECT DIR

    ARGUMENTS BUILD BUILD’S OUTPUT BUILD’S LOGGING TASK EXECUTED PLUGIN CLASS PATH
  17. Gradle TestKit @Test public void testHelloWorldTask() throws IOException { settingsFile

    = testProjectDir.newFile("settings.gradle"); buildFile = testProjectDir.newFile("build.gradle"); writeFile(settingsFile, "rootProject.name = 'hello-world'"); String buildFileContent = "task helloWorld {" + " doLast {" + " println 'Hello world!'" + " }" + "}"; writeFile(buildFile, buildFileContent); BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("helloWorld") .build(); assertTrue(result.getOutput().contains("Hello world!")); assertEquals(SUCCESS, result.task(":helloWorld").getOutcome()); }
  18. Gradle TestKit @Test public void testHelloWorldTask() throws IOException { settingsFile

    = testProjectDir.newFile("settings.gradle"); buildFile = testProjectDir.newFile("build.gradle"); writeFile(settingsFile, "rootProject.name = 'hello-world'"); String buildFileContent = "task helloWorld {" + " doLast {" + " println 'Hello world!'" + " }" + "}"; writeFile(buildFile, buildFileContent); BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("helloWorld") .build(); assertTrue(result.getOutput().contains("Hello world!")); assertEquals(SUCCESS, result.task(":helloWorld").getOutcome()); }
  19. Gradle TestKit given("Build Gradle File") { `when`("Talaiot is included with

    TaskDependencyGraph") { val buildFile = testProjectDir.newFile("build.gradle") buildFile.appendText( """ plugins { id 'java' id 'talaiot' } talaiot { publishers { taskDependencyGraphPublisher { gexf = true } } } """ )
  20. Gradle TestKit given("Build Gradle File") { `when`("Talaiot is included with

    TaskDependencyGraph") { val buildFile = testProjectDir.newFile("build.gradle") buildFile.appendText( """ plugins { id 'java' id 'talaiot' } talaiot { publishers { taskDependencyGraphPublisher { gexf = true } } } """ )
  21. Gradle TestKit val result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("assemble") .withPluginClasspath() .build()

    then("gexf files is generated") { assert(File(“${testProjectDir.getRoot()}/talaiot/gexfTaskDependency.gexf") .exists()) assert(result.task(":assemble")?.outcome == TaskOutcome.SUCCESS) }
  22. Gradle TestKit val result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("assemble") .withPluginClasspath() .build()

    then("gexf files is generated") { assert(File(“${testProjectDir.getRoot()}/talaiot/gexfTaskDependency.gexf") .exists()) assert(result.task(":assemble")?.outcome == TaskOutcome.SUCCESS) }
  23. Gradle TestKit val result = GradleRunner.create() .withProjectDir(testProjectDir.getRoot()) .withArguments("assemble") .withPluginClasspath() .build()

    then("gexf files is generated") { assert(File(“${testProjectDir.getRoot()}/talaiot/gexfTaskDependency.gexf") .exists()) assert(result.task(":assemble")?.outcome == TaskOutcome.SUCCESS) }