Share
Embed
Keeping your Gradle builds in top shape
Which tasks are the slowest running tasks?
Who has the slowest builds on my team?
Which task is getting the most cache misses?
These questions and more can be easily answered with the new Gradle Enterprise API.
Come learn about how to automatically check your build's cacheability and find out who on your team is suffering the most painful builds.
Nelson Osacky
July 07, 2022
Transcript
181 slides
-
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 -
I see a lot of builds from 10 person teams
to 1000+ Android, Gradle and Maven -
• Optimize and understand builds • Increase build stability •
Preach Developer Productivity -
• Improve Gradle ecosystem • Fix issues in open source
plugin affecting customers -
• Meet with Google and Jetbrains to help prioritize issues
impacting customers -
Cost of Builds 60s waste * 50 builds / day
* 50 devs = 42 hours lost / day -
Cost of Builds 60s waste * 50 builds / day
* 50 devs = 42 hours lost / day not including lost focus https://gradle.com/roi-calculator -
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 -
Slow builds are Tech Debt And it always pays off
And is easy to justify working on it -
JavaCompile task Source Files Compiler Args Dependencies Class files any
task can be made cacheable -
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 -
./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. -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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. -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
Tag a build // via build.gradle buildScan.tag("exp1-gradle") // via command
line system property -Dscan.tag.exp1-gradle -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
.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 -
> 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 -
> 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 -
> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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. -
./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 -
./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 -
./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 -
./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 -
./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 -
./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 -
./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 -
./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 -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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. -
./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. -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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. -
•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 -
./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. -
./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: <root directory> Gradle tasks: assemble Gradle arguments: <none> 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 -
./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 -
./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 -
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. -
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 -
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 -
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 -
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: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> Github Action to Verify Build -
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: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build -
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: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> # Run experiment 3 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build -
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: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> # Run experiment 2 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> # Run experiment 3 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/[email protected] with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build -
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 -
Old Export API • SSE based • Real time streaming
• JSON events • No event model • Clunky -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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", )) } -
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", )) } -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
fun main(args: Array<String>) = runBlocking<Unit> { 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 -
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) } -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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") } -
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 -
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.") } -
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.") } -
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.") } -
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.") } -
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.") } -
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.") } -
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.") } -
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 -
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") } -
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") } -
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") } -
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") } -
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") } -
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") } -
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") } -
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") } -
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 -
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}") } -
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}") } -
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 -
Usage: gradle-enterprise-project-summary A compact utility that gathers project metrics using
Gradle Enterprise API Options: --access-key-file=<accessKeyFile> The path to the file containing the access key --days=<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=<hours> The total number of hours to process from the past (if days set this will be ignored) --project-name=<projectName> The name of the project to show the builds of (if omitted, all builds are shown) --server-url=<serverUrl> The address of the Gradle Enterprise server --work-units=<nrOfWorkUnits> The number of tasks/goals to display Project summary -
{ "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 -
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/ -
•Absolute path sensitivity •Overlapping inputs and outputs •Non exclusive output
directory •Kapt removes contents of output directories -
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 -
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 -
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