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

Keeping your team in top shape with the Gradle Enterprise API

Keeping your team in top shape with the Gradle Enterprise API

5f69045a2ca496221cfc624405917cdf?s=128

Nelson Osacky

June 02, 2022
Tweet

More Decks by Nelson Osacky

Other Decks in Programming

Transcript

  1. Keeping your team in top shape Nelson Osacky with the

    Gradle Enterprise API
  2. 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
  3. I see a lot of builds from 10 person teams

    to 1000+ Android, Gradle and Maven
  4. • Optimize and understand builds • Increase build stability •

    Preach Developer Productivity
  5. • Improve Gradle ecosystem • Fix issues in open source

    plugin affecting customers
  6. • Meet with Google and Jetbrains to help prioritize issues

    impacting customers
  7. None
  8. Android Development Feature Development Tech Debt (There are other things

    too)
  9. Tech Debt Refactoring Improving builds

  10. Slow builds are Tech Debt And it always pays off

  11. Cost of Builds 60s waste * 50 builds / day

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

    * 50 devs 
 = 42 hours lost / day not including lost focus https://gradle.com/roi-calculator
  13. Fast Builds Matter

  14. 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
  15. Slow builds are Tech Debt And it always pays off

    And is easy to justify working on it
  16. None
  17. https://gradle.com/enterprise/trial/

  18. How many have seen or used a Build Scan?

  19. How many are Gradle Enterprise customers?

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

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

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

  23. JavaCompile task Source Files Compiler Args Dependencies Class files any

    task can be made cacheable
  24. Cache key Source Files Compiler Args Dependencies

  25. Cache key Source Files Compiler Args Dependencies Build cache Class

    files
  26. None
  27. Build Validation Scripts

  28. 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
  29. 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

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

    Validation Scripts
  31. ./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.
  32. ./01-validate-incremental-building.sh 2. ./gradlew clean assemble --no-build-cache 3. ./gradlew assemble --no-build-cache

  33. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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.
  34. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  35. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  36. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  37. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  38. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  39. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  40. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  41. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  42. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  43. Tag a build // via build.gradle buildScan.tag("exp1-gradle") // via command

    line system property -Dscan.tag.exp1-gradle
  44. ./01-validate-incremental-building.sh exp1-gradle

  45. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  46. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  47. ./01-validate-incremental-building.sh 6296b790

  48. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  49. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  50. .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
  51. > 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
  52. > 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
  53. > 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
  54. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  55. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  56. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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
  57. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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.
  58. ./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
  59. ./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
  60. Task execution overview

  61. ./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
  62. ./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
  63. Executed tasks timeline

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

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

  66. ./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
  67. ./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
  68. ./01-validate-incremental-building.sh https://ge.solutions-team.gradle.com/c/qocthanshmjdm/yj6btgctdvif6/task-inputs

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

  70. Task input comparison

  71. ./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
  72. ./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
  73. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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.
  74. ./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.
  75. ./01-validate-incremental-building.sh Summary ------- Project: android-cache-fix-gradle-plugin Git repo: git@github.com: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.
  76. •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
  77. ./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.
  78. ./02-validate-local-build-caching-same-location.sh 2. ./gradlew clean assemble --build-cache 3. ./gradlew clean assemble

    --build-cache
  79. ./02-validate-local-build-caching-same-location.sh Summary ------- Project: gradle-build-scan-quickstart Git repo: git@github.com: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 git@github.com:gradle/gradle-build-scan-quickstart.git -t assemble -s https:// ge.solutions-team.gradle.com
  80. ./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
  81. ./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
  82. 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.
  83. 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
  84. 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
  85. Automate it

  86. Github Action to Verify Build

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

  88. steps: # Download the latest version of the build validation

    scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/download@v1.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} Github Action to Verify Build
  89. steps: # Download the latest version of the build validation

    scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/download@v1.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/experiment-1@v1.0.2 with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> Github Action to Verify Build
  90. steps: # Download the latest version of the build validation

    scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/download@v1.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/experiment-1@v1.0.2 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/experiment-2@v1.0.2 with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build
  91. steps: # Download the latest version of the build validation

    scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/download@v1.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/experiment-1@v1.0.2 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/experiment-2@v1.0.2 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/experiment-3@v1.0.2 with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build
  92. steps: # Download the latest version of the build validation

    scripts - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/download@v1.0.2 with: token: ${{ secrets.GITHUB_TOKEN }} # Run experiment 1 - uses: gradle/gradle-enterprise-build-validation-scripts/.github/actions/gradle/experiment-1@v1.0.2 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/experiment-2@v1.0.2 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/experiment-3@v1.0.2 with: gitRepo: <PROJECT_GIT_URL> gitBranch: <PROJECT_BRANCH> tasks: <PROJECT_BUILD_TASK> ... Github Action to Verify Build
  93. https://github.com/gradle/gradle-enterprise-build-validation-scripts/tree/main/.github/actions/gradle Github Action to Verify Build Run them once a

    week!
  94. None
  95. Old Export API https://docs.gradle.com/enterprise/export-api/

  96. How many are are familiar with the Export API?

  97. Old Export API • SSE based • Real time streaming

    • JSON events • No event model • Clunky
  98. Old Export API https://«gradle-enterprise-host»/build-export/v2/builds/since/1466640000000

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

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

  103. 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
  104. None
  105. 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
  106. How to? • Swagger generates models and client for you

  107. plugins { kotlin("jvm") version "1.6.21" id("org.hidetake.swagger.generator") version "2.19.2" } build.gradle.kts

  108. plugins { kotlin("jvm") version "1.6.21" id("org.hidetake.swagger.generator") version "2.19.2" } val

    apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2- api.yaml" ).asFile() build.gradle.kts
  109. plugins { kotlin("jvm") version "1.6.21" id("org.hidetake.swagger.generator") version "2.19.2" } val

    apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2- api.yaml" ).asFile() sourceSets.create("client") sourceSets.create("model") build.gradle.kts
  110. plugins { kotlin("jvm") version "1.6.21" id("org.hidetake.swagger.generator") version "2.19.2" } val

    apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2- api.yaml" ).asFile() sourceSets.create("client") sourceSets.create("model") swaggerSources.configureEach { code.apply { language = "kotlin" inputFile = apiSpecificationFile configFile = file("openapi/openapi-generator-config.json") outputDir = file("${buildDir}/generated/$name") } } build.gradle.kts
  111. plugins { kotlin("jvm") version "1.6.21" id("org.hidetake.swagger.generator") version "2.19.2" } val

    apiSpecificationFile = resources.text.fromUri( "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-2022.2- api.yaml" ).asFile() sourceSets.create("client") sourceSets.create("model") swaggerSources.configureEach { code.apply { language = "kotlin" inputFile = apiSpecificationFile configFile = file("openapi/openapi-generator-config.json") outputDir = file("${buildDir}/generated/$name") } } build.gradle.kts
  112. None
  113. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  114. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  115. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  116. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  117. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  118. fun main(args: Array<String>) { ApiClient.accessToken = "ge-api-secret" val buildApi =

    BuildsApi("https://ge.solutions-team.gradle.com") val query = BuildsQuery(since = oneHourAgo) val builds = buildApi.getBuilds(query) builds.forEach { build -> println(build) } } Main.kt
  119. 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) }
  120. buildApi.getBuilds(query) buildApi.getGradleAttributes(build.id, null) buildApi.getGradleBuildCachePerformance(build.id, null)

  121. 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
  122. buildApi.getBuilds(query) buildApi.getGradleAttributes(build.id, null) buildApi.getGradleBuildCachePerformance(build.id, null)

  123. 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
  124. Project with slowest average build time

  125. 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
  126. 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
  127. 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
  128. 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
  129. 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
  130. 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
  131. 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") }
  132. 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
  133. User with slowest average build time

  134. 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.") }
  135. 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.") }
  136. 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.") }
  137. 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.") }
  138. 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.") }
  139. 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.") }
  140. 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.") }
  141. 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
  142. Tasks with highest negative avoidance savings

  143. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  144. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  145. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  146. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  147. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  148. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  149. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  150. Tasks with highest negative avoidance savings builds.filter { it.buildToolType ==

    "gradle" }.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") }
  151. 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
  152. User with the most build cache errors

  153. 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}") }
  154. Project with least avoidance savings

  155. 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}") }
  156. 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
  157. •Find slowest projects •Find slowest tasks •Find most active projects

    Project summary
  158. 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
  159. { "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
  160. None
  161. 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/
  162. https://ge.gradle.org/scans/tests?tests.sortField=MEAN_DURATION&tests.unstableOnly=true https://bit.ly/3DUBTu0

  163. How many use Room?

  164. •Absolute path sensitivity •Overlapping inputs and outputs •Non exclusive output

    directory •Kapt removes contents of output directories
  165. None
  166. Tweet, Like, Subscribe, Upvote, Star https://github.com/gradle/android-cache-fix-gradle-plugin https://issuetracker.google.com/issues/132245929 please star ⭐

    #fixroom
  167. None
  168. 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
  169. 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
  170. Predictive Test Selection https://gradle.com/gradle-enterprise-solutions/predictive-test-selection/

  171. 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
  172. Predictive Test Selection Simulator https://ge.spring.io/scans/test-selection

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