Slide 1

Slide 1 text

Keeping your Gradle builds in top shape Nelson Osacky

Slide 2

Slide 2 text

Me • Previously Android Engineer • Large projects • SoundCloud • Square • Small startups • Gradle Plugin Maintainer • Fladle - Easily Scale Instrumentation Tests on Firebase https://github.com/runningcode/fladle • Gradle Doctor - Actionable Insights for your build https://github.com/runningcode/gradle-doctor Lead Solutions Engineer

Slide 3

Slide 3 text

I see a lot of builds from 10 person teams to 1000+ Android, Gradle and Maven

Slide 4

Slide 4 text

• Optimize and understand builds • Increase build stability • Preach Developer Productivity

Slide 5

Slide 5 text

• Improve Gradle ecosystem • Fix issues in open source plugin affecting customers

Slide 6

Slide 6 text

• Meet with Google and Jetbrains to help prioritize issues impacting customers

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Android Development Feature Development Tech Debt (There are other things too)

Slide 9

Slide 9 text

Tech Debt Refactoring Improving builds

Slide 10

Slide 10 text

Slow builds are Tech Debt And it always pays off

Slide 11

Slide 11 text

Cost of Builds 60s waste * 50 builds / day * 50 devs 
 = 42 hours lost / day

Slide 12

Slide 12 text

Cost of Builds 60s waste * 50 builds / day * 50 devs 
 = 42 hours lost / day not including lost focus https://gradle.com/roi-calculator

Slide 13

Slide 13 text

Fast Builds Matter

Slide 14

Slide 14 text

Cost of Builds 60s waste * 50 builds / day * 50 devs 
 = 42 hours lost / day hire 5 new people without paying them! no recruiting https://gradle.com/roi-calculator

Slide 15

Slide 15 text

Slow builds are Tech Debt And it always pays off And is easy to justify working on it

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

https://gradle.com/enterprise/trial/

Slide 18

Slide 18 text

How many have seen or used a Build Scan?

Slide 19

Slide 19 text

How many are Gradle Enterprise customers?

Slide 20

Slide 20 text

https://gradle.com/enterprise-customers/oss-projects/ Gradle Enterprise OSS Projects

Slide 21

Slide 21 text

Quick Demo https://ge.androidx.dev/scans

Slide 22

Slide 22 text

What is build caching? https://docs.gradle.org/current/userguide/build_cache.html

Slide 23

Slide 23 text

JavaCompile task Source Files Compiler Args Dependencies Class files any task can be made cacheable

Slide 24

Slide 24 text

Cache key Source Files Compiler Args Dependencies

Slide 25

Slide 25 text

Cache key Source Files Compiler Args Dependencies Build cache Class files

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Build Validation Scripts

Slide 28

Slide 28 text

Build Validation Scripts 1. Verify up-to-date checking (incremental build) 2. Verify local cacheability 3. Verify cache relocateability 4. Verify CI to CI cache relocateability 5. Verify CI to Local machine cache relocateability

Slide 29

Slide 29 text

Build Validation Scripts 01-validate-incremental-building.sh 02-validate-local-build-caching-same-location.sh 03-validate-local-build-caching-different-locations.sh 04-validate-remote-build-caching-ci-ci.sh 05-validate-remote-build-caching-ci-local.sh

Slide 30

Slide 30 text

•Interactive mode with -i ./01-validate-incremental-building.sh -i •Command line invocation Build Validation Scripts

Slide 31

Slide 31 text

./01-validate-incremental-building.sh 1. Disable build caching completely 2. Run the build with a typical task invocation including the 'clean' task 3. Run the build with the same task invocation but without the 'clean' task 4. Determine which tasks are still executed in the second run and why 5. Assess which of the executed tasks are worth improving 6. Fix identified tasks Step 1-3 are automated. 4-6 are manual.

Slide 32

Slide 32 text

./01-validate-incremental-building.sh 2. ./gradlew clean assemble --no-build-cache 3. ./gradlew assemble --no-build-cache

Slide 33

Slide 33 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/timeline? outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/qocthanshmjdm/task-inputs Command Line Invocation ----------------------- ./01-validate-incremental-building.sh -r https://github.com/gradle/android-cache-fix-gradle-plugin -t assemble Once you have addressed the issues surfaced in build scans and pushed the changes to your Git repository, you can rerun the experiment and start over the cycle of run → measure → improve → run.

Slide 34

Slide 34 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 35

Slide 35 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 36

Slide 36 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 37

Slide 37 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 38

Slide 38 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 39

Slide 39 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 40

Slide 40 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 41

Slide 41 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 42

Slide 42 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 43

Slide 43 text

Tag a build // via build.gradle buildScan.tag("exp1-gradle") // via command line system property -Dscan.tag.exp1-gradle

Slide 44

Slide 44 text

./01-validate-incremental-building.sh exp1-gradle

Slide 45

Slide 45 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 46

Slide 46 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 47

Slide 47 text

./01-validate-incremental-building.sh 6296b790

Slide 48

Slide 48 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 49

Slide 49 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 50

Slide 50 text

.data/01-validate-incremental-building/20220531T194920-6296b790 ├── first-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ └── libs │ │ └── gradle-build-scan-quickstart.jar │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ │ └── java │ │ └── example │ │ └── Example.java │ └── test │ └── java │ └── example │ └── ExampleTest.java ├── second-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ ├── libs > tree .data/01-validate-incremental-building/20220531T194920-6296b790

Slide 51

Slide 51 text

> tree .data/01-validate-incremental-building/20220531T194920-6296b790 .data/01-validate-incremental-building/20220531T194920-6296b790 ├── first-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ └── libs │ │ └── gradle-build-scan-quickstart.jar │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ │ └── java │ │ └── example │ │ └── Example.java │ └── test │ └── java │ └── example │ └── ExampleTest.java ├── second-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ ├── libs

Slide 52

Slide 52 text

> tree .data/01-validate-incremental-building/20220531T194920-6296b790 .data/01-validate-incremental-building/20220531T194920-6296b790 ├── first-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ └── libs │ │ └── gradle-build-scan-quickstart.jar │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ │ └── java │ │ └── example │ │ └── Example.java │ └── test │ └── java │ └── example │ └── ExampleTest.java ├── second-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ ├── libs

Slide 53

Slide 53 text

> tree .data/01-validate-incremental-building/20220531T194920-6296b790 .data/01-validate-incremental-building/20220531T194920-6296b790 ├── first-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ └── libs │ │ └── gradle-build-scan-quickstart.jar │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── src │ ├── main │ │ └── java │ │ └── example │ │ └── Example.java │ └── test │ └── java │ └── example │ └── ExampleTest.java ├── second-build_gradle-build-scan-quickstart │ ├── README.md │ ├── build │ │ ├── classes │ │ │ └── java │ │ │ └── main │ │ │ └── example │ │ │ └── Example.class │ │ ├── libs

Slide 54

Slide 54 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 55

Slide 55 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 56

Slide 56 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm

Slide 57

Slide 57 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/timeline? outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/qocthanshmjdm/task-inputs Command Line Invocation ----------------------- ./01-validate-incremental-building.sh -r https://github.com/gradle/android-cache-fix-gradle-plugin -t assemble Once you have addressed the issues surfaced in build scans and pushed the changes to your Git repository, you can rerun the experiment and start over the cycle of run → measure → improve → run.

Slide 58

Slide 58 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 59

Slide 59 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 60

Slide 60 text

Task execution overview

Slide 61

Slide 61 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 62

Slide 62 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 63

Slide 63 text

Executed tasks timeline

Slide 64

Slide 64 text

Executed tasks timeline https://ge.solutions-team.gradle.com/s/lmjpnnl5nndpg/timeline?outcome=SUCCESS,FAILED&sort=longest

Slide 65

Slide 65 text

Executed tasks timeline https://ge.solutions-team.gradle.com/s/lmjpnnl5nndpg/timeline?outcome=SUCCESS,FAILED&sort=longest

Slide 66

Slide 66 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 67

Slide 67 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 68

Slide 68 text

./01-validate-incremental-building.sh https://ge.solutions-team.gradle.com/c/qocthanshmjdm/yj6btgctdvif6/task-inputs

Slide 69

Slide 69 text

./01-validate-incremental-building.sh https://ge.solutions-team.gradle.com/c/zj7wudbdhj7ho/lmjpnnl5nndpg/task-inputs

Slide 70

Slide 70 text

Task input comparison

Slide 71

Slide 71 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 72

Slide 72 text

./01-validate-incremental-building.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/ timeline?outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/ qocthanshmjdm/task-inputs

Slide 73

Slide 73 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/timeline? outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/qocthanshmjdm/task-inputs Command Line Invocation ----------------------- ./01-validate-incremental-building.sh -r https://github.com/gradle/android-cache-fix-gradle-plugin -t assemble Once you have addressed the issues surfaced in build scans and pushed the changes to your Git repository, you can rerun the experiment and start over the cycle of run → measure → improve → run.

Slide 74

Slide 74 text

./01-validate-incremental-building.sh Command Line Invocation ----------------------- ./01-validate-incremental-building.sh -r https://github.com/gradle/android-cache-fix-gradle-plugin -t assemble Once you have addressed the issues surfaced in build scans and pushed the changes to your Git repository, you can rerun the experiment and start over the cycle of run → measure → improve → run.

Slide 75

Slide 75 text

./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: [email protected]:gradle/android-cache-fix-gradle-plugin Git branch: main Git commit id: 88f52ce8c3b44a0563e21682866bc3f704107a52 Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 01 Validate incremental building Experiment id: exp1-gradle Experiment run id: 6296b790 Experiment artifact dir: .data/01-validate-incremental-building/20220531T194920-6296b790 Build scan first build: https://ge.solutions-team.gradle.com/s/yj6btgctdvif6 Build scan second build: https://ge.solutions-team.gradle.com/s/qocthanshmjdm Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qocthanshmjdm/timeline? outcome=SUCCESS,FAILED&sort=longest Task inputs comparison: https://ge.solutions-team.gradle.com/c/yj6btgctdvif6/qocthanshmjdm/task-inputs Command Line Invocation ----------------------- ./01-validate-incremental-building.sh -r https://github.com/gradle/android-cache-fix-gradle-plugin -t assemble Once you have addressed the issues surfaced in build scans and pushed the changes to your Git repository, you can rerun the experiment and start over the cycle of run → measure → improve → run.

Slide 76

Slide 76 text

•Interactive mode with -i ./01-validate-incremental-building.sh -i •Command line invocation ./01-validate-incremental-building.sh -r https:// github.com/gradle/android-cache-fix-gradle-plugin -t assemble Build Validation Scripts

Slide 77

Slide 77 text

./02-validate-local-build-caching-same-location.sh 1. Enable only local build caching and use an empty local build cache 2. Run the build with a typical task invocation including the ‘clean’ task 3. Run the build with the same task invocation including the ‘clean’ task 4. Determine which cacheable tasks are still executed in the second run and why 5. Assess which of the executed, cacheable tasks are worth improving 6. Fix identified tasks Step 1-3 are automated. 4-6 are manual.

Slide 78

Slide 78 text

./02-validate-local-build-caching-same-location.sh 2. ./gradlew clean assemble --build-cache 3. ./gradlew clean assemble --build-cache

Slide 79

Slide 79 text

./02-validate-local-build-caching-same-location.sh Summary ------- Project: gradle-build-scan-quickstart Git repo: [email protected]:gradle/gradle-build-scan-quickstart.git Git branch: main Git commit id: 3157cfc52db2c1ac960dcb2c24c4cbe3603c92be Project dir: Gradle tasks: assemble Gradle arguments: Experiment: 02 Validate local build caching - same project location Experiment id: exp2-gradle Experiment run id: 6298cd0f Experiment artifact dir: .data/02-validate-local-build-caching-same-location/20220602T074535-6298cd0f Build scan first build: https://ge.solutions-team.gradle.com/s/zoloexid3t4ok Build scan second build: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?outcome=SUCCESS,FAILED&sort=longest Executed cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline? cacheability=cacheable,overlapping_outputs,validation_failure&outcome=SUCCESS,FAILED&sort=longest Executed non-cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?cacheability=any_non- cacheable&outcome=SUCCESS,FAILED&sort=longest Build caching statistics: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/build-cache Task inputs comparison: https://ge.solutions-team.gradle.com/c/zoloexid3t4ok/a6uhbkyvlexug/task-inputs?cacheability=cacheable Command Line Invocation ----------------------- ./02-validate-local-build-caching-same-location.sh -r [email protected]:gradle/gradle-build-scan-quickstart.git -t assemble -s https:// ge.solutions-team.gradle.com

Slide 80

Slide 80 text

./02-validate-local-build-caching-same-location.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?outcome=SUCCESS,FAILED&sort=longest Executed cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline? cacheability=cacheable,overlapping_outputs,validation_failure&outcome=SUCCESS,FAILED&sort=longest Executed non-cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?cacheability=any_non- cacheable&outcome=SUCCESS,FAILED&sort=longest Build caching statistics: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/build-cache Task inputs comparison: https://ge.solutions-team.gradle.com/c/zoloexid3t4ok/a6uhbkyvlexug/task-inputs?cacheability=cacheable

Slide 81

Slide 81 text

./02-validate-local-build-caching-same-location.sh Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?outcome=SUCCESS,FAILED&sort=longest Executed cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline? cacheability=cacheable,overlapping_outputs,validation_failure&outcome=SUCCESS,FAILED&sort=longest Executed non-cacheable tasks: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/timeline?cacheability=any_non- cacheable&outcome=SUCCESS,FAILED&sort=longest Build caching statistics: https://ge.solutions-team.gradle.com/s/a6uhbkyvlexug/performance/build-cache Task inputs comparison: https://ge.solutions-team.gradle.com/c/zoloexid3t4ok/a6uhbkyvlexug/task-inputs?cacheability=cacheable

Slide 82

Slide 82 text

1. Enable only local build caching and use an empty local build cache 2. Run the build with a typical task invocation including the ‘clean’ task 3. Run the build from a different location with the same task invocation including the ‘clean’ task 4. Determine which cacheable tasks are still executed in the second run and why 5. Assess which of the executed, cacheable tasks are worth improving 6. Fix identified tasks ./03-validate-local-build-caching-different-locations.sh Step 1-3 are automated. 4-6 are manual.

Slide 83

Slide 83 text

1. Enable only remote build caching and use an empty remote build cache 2. On a given CI agent, run a typical CI configuration from a fresh checkout 3. On another CI agent, run the same CI configuration with the same commit id from a fresh checkout 4. Determine which cacheable tasks are still executed in the second run and why 5. Assess which of the executed, cacheable tasks are worth improving 6. Fix identified tasks ./04-validate-remote-build-caching-ci-ci.sh All steps are manual

Slide 84

Slide 84 text

1. Enable only remote build caching and use an empty remote build cache 2. On a given CI agent, run a typical CI configuration from a fresh checkout 3. On a developer machine, run the build with the same task invocation including the ‘clean’ task with the same commit id 4. Determine which cacheable tasks are still executed in the second run and why 5. Assess which of the executed, cacheable tasks are worth improving 6. Fix identified tasks ./05-validate-remote-build-caching-ci-local.sh All steps are manual except step 3

Slide 85

Slide 85 text

Automate it

Slide 86

Slide 86 text

Github Action to Verify Build

Slide 87

Slide 87 text

https://github.com/gradle/gradle-enterprise-build-validation-scripts/tree/main/.github/actions/gradle Github Action to Verify Build

Slide 88

Slide 88 text

steps: # Download the latest version of the build validation scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} Github Action to Verify Build

Slide 89

Slide 89 text

steps: # Download the latest version of the build validation scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: Github Action to Verify Build

Slide 90

Slide 90 text

steps: # Download the latest version of the build validation scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: ... Github Action to Verify Build

Slide 91

Slide 91 text

steps: # Download the latest version of the build validation scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: # Run experiment 3 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: ... Github Action to Verify Build

Slide 92

Slide 92 text

steps: # Download the latest version of the build validation scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: # Run experiment 3 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: gitBranch: tasks: ... Github Action to Verify Build

Slide 93

Slide 93 text

https://github.com/gradle/gradle-enterprise-build-validation-scripts/tree/main/.github/actions/gradle Github Action to Verify Build Run them once a week!

Slide 94

Slide 94 text

https://github.com/gradle/gradle-enterprise-oss-projects/actions/runs/2604518317 AndroidX Execution

Slide 95

Slide 95 text

Summary ------- Project: biometric-playground Git repo: https://github.com/gradle/androidx Git branch: androidx-main Git commit id: e1f0de767e6002ead5488f35152fe4a97036d1e5 Project dir: biometric Gradle tasks: buildOnServer zipTestConfigsWithApks test Gradle arguments: -x ktlint Experiment: 03 Validate local build caching - different project locations Experiment id: exp3-gradle Experiment run id: 62c15afb Experiment artifact dir: .data/03-validate-local-build-caching-different-locations/20220703T090147-62c15afb Build scan first build: https://ge.solutions-team.gradle.com/s/dh6hbujtzul6s Build scan second build: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa Investigation Quick Links ------------------------- Task execution overview: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa/performance/execution Executed tasks timeline: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa/timeline? outcome=SUCCESS,FAILED&sort=longest Executed cacheable tasks: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa/timeline? cacheability=cacheable,overlapping_outputs,validation_failure&outcome=SUCCESS,FAILED&sort=longest Executed non-cacheable tasks: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa/timeline?cacheability=any_non- cacheable&outcome=SUCCESS,FAILED&sort=longest Build caching statistics: https://ge.solutions-team.gradle.com/s/qlijsh5r36vqa/performance/build-cache Task inputs comparison: https://ge.solutions-team.gradle.com/c/dh6hbujtzul6s/qlijsh5r36vqa/task-inputs? cacheability=cacheable https://github.com/gradle/gradle-enterprise-oss-projects/runs/7167693674?check_suite_focus=true#step:9:3214

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

Old Export API https://docs.gradle.com/enterprise/export-api/

Slide 98

Slide 98 text

How many are are familiar with the Export API?

Slide 99

Slide 99 text

Old Export API • SSE based • Real time streaming • JSON events • No event model • Clunky

Slide 100

Slide 100 text

Old Export API https://«gradle-enterprise-host»/build-export/v2/builds/since/1466640000000

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

Old Export API https://«gradle-enterprise-host»/build-export/v2/build/gkoprlkauv35q/events

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

New Gradle Enterprise API https://docs.gradle.com/enterprise/api-manual/

Slide 105

Slide 105 text

Gradle Enterprise API • REST style API • JSON • OpenAPI - allows model and client generation • Build API • Build Cache Node API • Will replace export API - missing raw build events

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

Use cases • Find projects with longest build times • Rank teammates by slowest average build time • Find builds with remote caching errors • Find slowest tasks on average • Find longest non-cacheable tasks in all projects

Slide 108

Slide 108 text

How to? • Swagger generates models and client for you

Slide 109

Slide 109 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 110

Slide 110 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 111

Slide 111 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 112

Slide 112 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 113

Slide 113 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 114

Slide 114 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 115

Slide 115 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 116

Slide 116 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) } build.gradle.kts

Slide 117

Slide 117 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) }

Slide 118

Slide 118 text

plugins { kotlin("jvm") version "1.7.0" id("org.openapi.generator") version "6.0.0" } val apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2.4- api.yaml" ).asFile() val outputDirName = "${buildDir}/generated/gradle_enterprise_api" openApiGenerate { generatorName.set("kotlin") inputSpec.set(apiSpecificationFile.absolutePath) outputDir.set(outputDirName) modelPackage.set("com.gradle.enterprise.api.model") apiPackage.set("com.gradle.enterprise.api") invokerPackage.set("com.gradle.enterprise.api.client") configOptions.set(mapOf( "library" to "jvm-retrofit2", "useCoroutines" to "true", )) }

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 121

Slide 121 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 122

Slide 122 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 123

Slide 123 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 124

Slide 124 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 125

Slide 125 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 126

Slide 126 text

fun main(args: Array) = runBlocking { val apiClient = ApiClient( baseUrl = "https://ge.solutions-team.gradle.com", authName = "GradleEnterpriseAccessKey", bearerToken = "my-secret-token" ) val buildApi = apiClient.createService(BuildsApi::class.java) val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt

Slide 127

Slide 127 text

Build(id=wsj4fsafsadte, availableAt=1654106260326, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qsj4euf5g3dff, availableAt=1654106224428, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=dsjaadff5g3te, availableAt=1654101266539, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=yweroijiwerjr, availableAt=1654109460322, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=wsj4fsafsadte, availableAt=1654106260326, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qsj4euf5g3dff, availableAt=1654106224428, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=dsjaadff5g3te, availableAt=1654101266539, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=yweroijiwerjr, availableAt=1654109460322, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qwerwerwerwer, availableAt=1654106260326, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qsj4euf5g3dff, availableAt=1654106224428, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=dsjaadff5g3te, availableAt=1654101266539, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=yweroijiwerjr, availableAt=1654109460322, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qweorijweroiw, availableAt=1654106260326, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qsj4euf5g3dff, availableAt=1654106224428, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=dsjaadff5g3te, availableAt=1654101266539, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=yweroijiwerjr, availableAt=1654109460322, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=wsj4fsafsadte, availableAt=1654106260326, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qsj4euf5g3dff, availableAt=1654106224428, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=dsjaadff5g3te, availableAt=1654101266539, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) Build(id=qweroijwerijr, availableAt=1654109324464, buildToolType=gradle, buildToolVersion=7.4.2, buildAgentVersion=3.10.1) builds.forEach { build -> println(build) }

Slide 128

Slide 128 text

buildApi.getBuilds(query) buildApi.getGradleAttributes(build.id, null) buildApi.getGradleBuildCachePerformance(build.id, null)

Slide 129

Slide 129 text

buildApi.getGradleAttributes(build.id, null) { • "id": "9r4d13f0r3v3r", • "buildStartTime": 1637316480, • "buildDuration": 5000, • "gradleVersion": "7.3", • "pluginVersion": "3.7.2", • "rootProjectName": "example-project", • "requestedTasks": [ • "clean", • "build" • ], • "hasFailed": false, • "tags": [ • "CI", • "feature-branch" • ], • "values": [ • {}, • {} • ], • "links": [ • {}, • {} • ], • "gradleEnterpriseSettings": { • "backgroundPublicationEnabled": true, • "buildOutputCapturingEnabled": true, • "taskInputsFileCapturingEnabled": true, • "testOutputCapturingEnabled": true • }, • "buildOptions": { • "buildCacheEnabled": true, • "configurationCacheEnabled": true, • "configurationOnDemandEnabled": true, https://docs.gradle.com/enterprise/api-manual/ref/2022.2.html#operation/GetGradleAttributes

Slide 130

Slide 130 text

buildApi.getBuilds(query) buildApi.getGradleAttributes(build.id, null) buildApi.getGradleBuildCachePerformance(build.id, null)

Slide 131

Slide 131 text

buildApi.getGradleBuildCachePerformance(build.id, null) { • "id": "9r4d13f0r3v3r", • "buildTime": 5000, • "effectiveTaskExecutionTime": 4000, • "serialTaskExecutionTime": 8000, • "serializationFactor": 2, • "taskExecution": [ • {}, • {} • ], • "taskFingerprintingSummary": { • "count": 1, • "serialDuration": 8 • }, • "avoidanceSavingsSummary": { • "total": 10000, • "ratio": 0.55556, • "upToDate": 0, • "localBuildCache": 6000, • "remoteBuildCache": 4000 • }, • "buildCaches": { • "local": {}, • "remote": {}, • "overhead": {} • } } https://docs.gradle.com/enterprise/api-manual/ref/2022.2.html#operation/GetGradleBuildCacheP

Slide 132

Slide 132 text

Project with slowest average build time

Slide 133

Slide 133 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 134

Slide 134 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 135

Slide 135 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 136

Slide 136 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 137

Slide 137 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 138

Slide 138 text

builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project with slowest average build time

Slide 139

Slide 139 text

Project with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") }

Slide 140

Slide 140 text

Project with slowest average build time .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Project ${pair.first} has average build time of ${seconds}s") } Project customer-app has average build time of 184s Project internal-app has average build time of 55s Project time-lib has average build time of 20s

Slide 141

Slide 141 text

User with slowest average build time

Slide 142

Slide 142 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 143

Slide 143 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 144

Slide 144 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 145

Slide 145 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 146

Slide 146 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 147

Slide 147 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 148

Slide 148 text

User with slowest average build time builds.map { build -> buildApi.getGradleAttributes(build.id, null) } .groupBy { it.environment.username } .map { (username, userBuilds) -> username to userBuilds.map { it.buildDuration }.average() } .sortedByDescending { pair -> pair.second } .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") }

Slide 149

Slide 149 text

User with slowest average build time .forEach { pair -> val seconds = TimeUnit.MILLISECONDS.toSeconds(pair.second.toLong()) println("Username: ${pair.first}, average build time is ${seconds}s.") } Username: sorin, average build time is 233s Username: daz, average build time is 122s Username: gary, average build time is 33s Username: alexis, average build time is 30s Username: jerome, average build time is 29s Username: clay, average build time is 20s Username: etienne, average build time is 20s

Slide 150

Slide 150 text

Tasks with highest negative avoidance savings

Slide 151

Slide 151 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sortedByDescending { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 152

Slide 152 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sortedByDescending { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 153

Slide 153 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sortedByDescending { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 154

Slide 154 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sortedByDescending { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 155

Slide 155 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sortedByDescending { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 156

Slide 156 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sorted { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 157

Slide 157 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sorted { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 158

Slide 158 text

Tasks with highest negative avoidance savings builds.map { build -> buildApi.getGradleBuildCachePerformance(build.id, null) } .flatMap { it.taskExecution.filter { (it.avoidanceSavings ?: 0) < 0 } } .groupBy { it.taskPath } .map { (taskPath, taskExecutions) -> taskPath to taskExecutions.map { it.avoidanceSavings!! }.average() } .sorted { pair -> pair.second } .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") }

Slide 159

Slide 159 text

Tasks with highest negative avoidance savings .forEach { (taskPath, averageAvoidanceSavings) -> println("Task $taskPath has average avoidance savings $averageAvoidanceSavings") } Task :app:mergeNativeDebugLibs has average avoidance savings -23s Task :app:dataBindingMergeGenClassesDebug has average avoidance savings -10s Task :app:compileDebugAidl has average avoidance savings -2s Task :lib:mergeDebugConsumerProguardFiles has average avoidance savings -1s

Slide 160

Slide 160 text

User with the most build cache errors

Slide 161

Slide 161 text

User with the most build cache errors builds.map { buildApi.getGradleAttributes(it.id, null) to buildApi.getGradleBuildCachePerformance(it.id, null) } .groupBy {it.first.environment.username} .map { (username, buildPairs) -> username to buildPairs.count { it.second.buildCaches?.remote?.isDisabledDueToError ?: false } } .sortedByDescending { pair -> pair.second } .forEach { pair -> println("Username: ${pair.first}, total builds disabled due to errors: $ {pair.second}") }

Slide 162

Slide 162 text

Project with least avoidance savings

Slide 163

Slide 163 text

Project with least avoidance savings builds.map { buildApi.getGradleAttributes(it.id, null) to buildApi.getGradleBuildCachePerformance(it.id, null) } .groupBy { it.first.rootProjectName } .map { (projectName, projectBuilds) -> projectName to projectBuilds.map { it.second.avoidanceSavingsSummary.ratio }.average() } .sortedBy { pair -> pair.second } .forEach { pair -> val ratio = pair.second println("Project ${pair.first} with average avoidance savings ratio of ${ratio}") }

Slide 164

Slide 164 text

builds.filter { it.buildToolType == "gradle" }.map { build -> buildApi.getGradleAttributes(build.id, null) }.filter { it.tags.contains("doctor-negative-avoidance-savings") } Find builds with certain tags

Slide 165

Slide 165 text

•Find slowest projects •Find slowest tasks •Find most active projects Project summary

Slide 166

Slide 166 text

Usage: gradle-enterprise-project-summary A compact utility that gathers project metrics using Gradle Enterprise API Options: --access-key-file= The path to the file containing the access key --days= The total number of days to process from the past (if set will ignore hours) --format-duration Formatting the durations by HH:mm:ss --hours= The total number of hours to process from the past (if days set this will be ignored) --project-name= The name of the project to show the builds of (if omitted, all builds are shown) --server-url= The address of the Gradle Enterprise server --work-units= The number of tasks/goals to display Project summary

Slide 167

Slide 167 text

{ "summary" : { "totalNumberOfBuilds" : "3170", "totalBuildTime" : "631261486", "totalNumberOfUsers" : "16", "totalNumberOfProjects" : "6" }, "projects" : { "main-app" : { "totalNumberOfBuilds" : "3130", "buildTime" : "627827767", "numOfUsers" : "14", "totalTaskExecutionTime" : "487443385", "totalTaskAvoidanceTime" : "2805217043", "totalTaskAvoidableTime" : "138022728", "totalTaskNonAvoidableTime" : "370605501", "tasks" : { "test" : { "totalExecutions" : "7365", "totalTaskExecutionTime" : "68277014", "totalTaskAvoidanceTime" : "235514732", "totalTaskAvoidableTime" : "46062541", "totalTaskNonAvoidableTime" : "21259161", "cacheMissRate" : "9" }, "test_Maven_3_8_5_daily_JDK_18" : { "totalExecutions" : "12", "totalTaskExecutionTime" : "12751161", "totalTaskAvoidanceTime" : "0", "totalTaskAvoidableTime" : "12751161", "totalTaskNonAvoidableTime" : "0", "cacheMissRate" : "100" }, "test_Maven_3_8_5" : { "totalExecutions" : "41", "totalTaskExecutionTime" : "14975383", "totalTaskAvoidanceTime" : "0", "totalTaskAvoidableTime" : "12439278", "totalTaskNonAvoidableTime" : "2536105", Project summary

Slide 168

Slide 168 text

No content

Slide 169

Slide 169 text

Gradle Enterprise Android Features • Find your slowest tests in the test dashboard • Learn which tests are flaky with flaky test insights • Android Instrumentation Test results in Build Scans! Check it out! https://gradle.com/enterprise-customers/oss-projects/

Slide 170

Slide 170 text

https://ge.gradle.org/scans/tests?tests.sortField=MEAN_DURATION&tests.unstableOnly=true https://bit.ly/3DUBTu0

Slide 171

Slide 171 text

How many use Room?

Slide 172

Slide 172 text

•Absolute path sensitivity •Overlapping inputs and outputs •Non exclusive output directory •Kapt removes contents of output directories

Slide 173

Slide 173 text

No content

Slide 174

Slide 174 text

Tweet, Like, Subscribe, Upvote, Star https://github.com/gradle/android-cache-fix-gradle-plugin https://issuetracker.google.com/issues/132245929 please star ⭐ #fixroom

Slide 175

Slide 175 text

No content

Slide 176

Slide 176 text

More Resources Gradle Training https://gradle.com/training/ https://gradle.com/training/introduction-to-gradle https://gradle.com/training/build-cache-deep-dive Gradle Community Slack https://gradle.com/slack-invite https://github.com/gradle/gradle-enterprise-build-validation-scripts https://docs.gradle.com/enterprise/api-manual/ https://github.com/gradle/gradle-enterprise-api-samples

Slide 177

Slide 177 text

Thank you! Gradle Enterprise Trial osacky.com https://gradle.com/enterprise/trial/ https://go.gradle.com/solutions-engineer https://gradle.com/careers/ Gradle Solutions is hiring #fixroom @nellyspageli https://github.com/gradle/gradle-enterprise-build-validation-scripts https://docs.gradle.com/enterprise/api-manual/ https://github.com/gradle/gradle-enterprise-api-samples https://speakerdeck.com/runningcode/keeping-your-gradle-builds-in-top-shape Room bug Slides

Slide 178

Slide 178 text

Predictive Test Selection https://gradle.com/gradle-enterprise-solutions/predictive-test-selection/

Slide 179

Slide 179 text

Predictive Test Selection • Machine learning selects tests which provide useful feedback • 99% accuracy, save 60% of testing time • Predictive Test Selection Simulator • See why tests were selected in dashboard • Not yet available for Android Instrumentation Tests https://ge.micronaut.io/scans/test-selection

Slide 180

Slide 180 text

Predictive Test Selection Simulator https://ge.spring.io/scans/test-selection

Slide 181

Slide 181 text

Predictive Test Selection https://ge.gradle.org/scans/test-selection