From 760b61ccafc3471a5c38c2399acad302fb5b61e4 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Wed, 10 May 2023 16:20:07 +0200
Subject: [PATCH 01/57] Initial

---
 .../build-scan-data-loader-api/build.gradle.kts   |  3 +++
 .../enterprise/loader/BuildScanDataLoader.java    |  9 +++++++++
 .../build.gradle.kts                              |  7 +++++++
 .../loader/OfflineBuildScanDataLoader.java        | 15 +++++++++++++++
 .../build.gradle.kts                              |  7 +++++++
 .../loader/OnlineBuildScanDataLoader.java         | 15 +++++++++++++++
 settings.gradle.kts                               |  6 ++++++
 7 files changed, 62 insertions(+)
 create mode 100644 components/build-scan-data-loader-api/build.gradle.kts
 create mode 100644 components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
 create mode 100644 components/build-scan-data-loader-offline/build.gradle.kts
 create mode 100644 components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
 create mode 100644 components/build-scan-data-loader-online/build.gradle.kts
 create mode 100644 components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
new file mode 100644
index 00000000..b600092f
--- /dev/null
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -0,0 +1,3 @@
+plugins {
+    id("java-library")
+}
diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
new file mode 100644
index 00000000..074f0b2c
--- /dev/null
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -0,0 +1,9 @@
+package com.gradle.enterprise.loader;
+
+public interface BuildScanDataLoader {
+
+    String loadDataForGradle();
+
+    String loadDataForMaven();
+
+}
diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
new file mode 100644
index 00000000..227452f8
--- /dev/null
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+    id("java-library")
+}
+
+dependencies {
+    api(project(":build-scan-data-loader-api"))
+}
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
new file mode 100644
index 00000000..1b0cd014
--- /dev/null
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -0,0 +1,15 @@
+package com.gradle.enterprise.loader;
+
+public class OfflineBuildScanDataLoader implements BuildScanDataLoader {
+
+    @Override
+    public String loadDataForGradle() {
+        return null;
+    }
+
+    @Override
+    public String loadDataForMaven() {
+        return null;
+    }
+
+}
diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
new file mode 100644
index 00000000..227452f8
--- /dev/null
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+    id("java-library")
+}
+
+dependencies {
+    api(project(":build-scan-data-loader-api"))
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
new file mode 100644
index 00000000..2a47c584
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -0,0 +1,15 @@
+package com.gradle.enterprise.loader;
+
+public class OnlineBuildScanDataLoader implements BuildScanDataLoader {
+
+    @Override
+    public String loadDataForGradle() {
+        return null;
+    }
+
+    @Override
+    public String loadDataForMaven() {
+        return null;
+    }
+
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f841fa84..784c6eea 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -37,6 +37,12 @@ rootProject.name = "build-validation-scripts"
 
 include("components/configure-gradle-enterprise-maven-extension")
 include("components/fetch-build-scan-data-cmdline-tool")
+include("components/build-scan-data-loader-api")
+include("components/build-scan-data-loader-online")
+include("components/build-scan-data-loader-offline")
 
 project(":components/configure-gradle-enterprise-maven-extension").name = "configure-gradle-enterprise-maven-extension"
 project(":components/fetch-build-scan-data-cmdline-tool").name = "fetch-build-scan-data-cmdline-tool"
+project(":components/build-scan-data-loader-api").name = "build-scan-data-loader-api"
+project(":components/build-scan-data-loader-online").name = "build-scan-data-loader-online"
+project(":components/build-scan-data-loader-offline").name = "build-scan-data-loader-offline"

From cc0854e521e72cb50db2f6a784c4a69093f1b376 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Wed, 10 May 2023 16:29:32 +0200
Subject: [PATCH 02/57] Add OpenApi generator to api module

---
 .../.openapi-generator-ignore                 |    7 +
 .../build.gradle.kts                          |   55 +
 .../src/main/openapi/openapi.yaml             | 2059 +++++++++++++++++
 .../build.gradle.kts                          |    7 +
 .../build.gradle.kts                          |    7 +
 5 files changed, 2135 insertions(+)
 create mode 100644 components/build-scan-data-loader-api/.openapi-generator-ignore
 create mode 100644 components/build-scan-data-loader-api/src/main/openapi/openapi.yaml

diff --git a/components/build-scan-data-loader-api/.openapi-generator-ignore b/components/build-scan-data-loader-api/.openapi-generator-ignore
new file mode 100644
index 00000000..d70ed322
--- /dev/null
+++ b/components/build-scan-data-loader-api/.openapi-generator-ignore
@@ -0,0 +1,7 @@
+build/generated/gradle_enterprise_api/*
+build/generated/gradle_enterprise_api/.github/*
+build/generated/gradle_enterprise_api/api/*
+build/generated/gradle_enterprise_api/docs/*
+build/generated/gradle_enterprise_api/gradle/**/*
+build/generated/gradle_enterprise_api/src/main/AndroidManifest.xml
+build/generated/gradle_enterprise_api/src/test/**/*
diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index b600092f..712bba40 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -1,3 +1,58 @@
 plugins {
     id("java-library")
+    id("org.openapi.generator") version "6.5.0"
 }
+
+repositories {
+    mavenCentral()
+}
+
+// todo review dependencies
+dependencies {
+    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
+    implementation("com.squareup.okhttp3:okhttp")
+    implementation("com.squareup.okhttp3:okhttp-tls")
+    implementation("com.squareup.okhttp3:logging-interceptor")
+
+    implementation("io.swagger:swagger-annotations:1.6.10")
+    implementation("io.gsonfire:gson-fire:1.8.5")
+    implementation("javax.ws.rs:jsr311-api:1.1.1")
+    implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
+
+    implementation("com.google.guava:guava:31.1-jre")
+}
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(8))
+        vendor.set(JvmVendorSpec.AZUL)
+    }
+}
+
+openApiGenerate {
+    generatorName.set("java")
+    inputSpec.set("$projectDir/src/main/openapi/openapi.yaml")
+    outputDir.set("$buildDir/generated/gradle_enterprise_api")
+    ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
+    modelPackage.set("com.gradle.enterprise.api.model")
+    apiPackage.set("com.gradle.enterprise.api")
+    invokerPackage.set("com.gradle.enterprise.api.client")
+    // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
+    configOptions.set(mapOf(
+            "library" to "okhttp-gson",
+            "dateLibrary" to "java8",
+            "hideGenerationTimestamp" to "true",
+            "openApiNullable" to "false",
+            "useBeanValidation" to "false",
+            "disallowAdditionalPropertiesIfNotPresent" to "false",
+            "sourceFolder" to ""  // makes IDEs like IntelliJ more reliably interpret the class packages.
+    ))
+}
+
+sourceSets {
+    main {
+        java {
+            srcDir(tasks.openApiGenerate)
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml b/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
new file mode 100644
index 00000000..0376bafb
--- /dev/null
+++ b/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
@@ -0,0 +1,2059 @@
+openapi: 3.0.3
+info:
+  title: Gradle Enterprise API
+  description: >
+    The Gradle Enterprise API allows programmatic interaction with various
+    aspects of Gradle Enterprise, from configuration to inspecting build data.
+  version: "2022.2.4"
+  license:
+    name: Gradle Enterprise License
+    url: https://gradle.com/legal/gradle-enterprise-software-agreement
+  termsOfService: https://gradle.com/legal/terms-of-service
+  contact:
+    name: Gradle
+    url: https://gradle.com
+  x-logo:
+    url: https://assets.gradle.com/logo/gradle-enterprise-dark-green-primary.svg
+    altText: Gradle Enterprise
+servers:
+  - url: https://ge.mycompany.com
+    description: Your Gradle Enterprise instance.
+security:
+  - GradleEnterpriseAccessKey: []
+paths:
+  /api/builds:
+    description: >
+      Returns a list of builds with basic attributes of a Build Scan. The
+      returned list is capped by the `maxBuilds` and `maxWaitSecs` query
+      parameters. This
+
+      endpoint supports pagination by using the `sinceBuild` query parameter,
+      and the last returned build from a previous call to this endpoint, one can
+      get
+
+      the next batch of builds.
+    parameters:
+      - in: query
+        name: BuildsQuery
+        explode: true
+        schema:
+          title: BuildsQuery
+          type: object
+          properties:
+            since:
+              type: integer
+              format: int64
+              minimum: 0
+              x-nullable: true
+              description: >
+                The time in milliseconds from the Epoch as of when the Build
+                Scan has been received. A value of `0` will process all builds.
+                If not provided, the time
+
+                in milliseconds when the request is received by the Gradle
+                Enterprise instance will be used. This parameter has no effect
+                if `sinceBuild` is used.
+            sinceBuild:
+              type: string
+              x-nullable: true
+              description: >
+                A Build Scan ID allowing to retrieve builds for which Gradle
+                Enterprise completed receiving and processing after the given
+                Build Scan ID (excluding it).
+
+                This parameter has precedence over any value set for the `since`
+                parameter. A valid Build Scan ID must be provided, that is, a
+                Build Scan ID that exists
+
+                in the Gradle Enterprise instance. A Build Scan ID for a deleted
+                build is valid.
+            maxBuilds:
+              type: integer
+              minimum: 0
+              maximum: 1000
+              x-nullable: true
+              description: >
+                The maximum number of builds returned by the query. The query
+                returns when that number is reached or when `maxWaitSecs` is
+                reached.
+
+                If not provided, the default value is `100`.
+            maxWaitSecs:
+              type: integer
+              minimum: 1
+              maximum: 20
+              x-nullable: true
+              description: >
+                The maximum number of seconds to wait for builds before
+                returning. If this time is reached before `maxBuilds` is
+                reached, the query returns with the
+
+                already processed builds. Note that this time is respected with
+                best effort. A query will return soon after this time has passed
+                but there is no 
+
+                guarantee that it exactly returns before this time has passed.
+                If not provided, the default value is `3`.
+    get:
+      operationId: GetBuilds
+      summary: Get a list of builds with basic attributes of a Build Scan.
+      description: The contained attributes are build tool agnostic.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: A list of builds with basic attributes of a Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Builds'
+              example:
+                - id: 9r4d13f0r3v3r
+                  availableAt: 1635400481000
+                  buildToolType: gradle
+                  buildToolVersion: '7.2'
+                  buildAgentVersion: 3.7.1
+                - id: ji7vz3ey5qdvk
+                  availableAt: 1635400482000
+                  buildToolType: maven
+                  buildToolVersion: 3.8.4
+                  buildAgentVersion: '1.13'
+                - id: cvpd4j7ug7j4q
+                  availableAt: 1635400483000
+                  buildToolType: bazel
+                  buildToolVersion: 6.0.0
+                  buildAgentVersion: '1.0'
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetBuild
+      summary: Get the common attributes of a Build Scan.
+      description: The contained attributes are build tool agnostic.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The common attributes of a Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Build'
+              example:
+                id: 9r4d13f0r3v3r
+                availableAt: 1635400481000
+                buildToolType: gradle
+                buildToolVersion: '7.2'
+                buildAgentVersion: 3.7.1
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-attributes:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleAttributes
+      summary: Get the attributes of a Gradle Build Scan.
+      description: >-
+        This model is Gradle specific and cannot be requested for another build
+        tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The attributes of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleAttributes'
+              example:
+                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:
+                  - name: branch
+                    value: feature/one
+                  - name: commitId
+                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                links:
+                  - label: CI job
+                    url: https://ci.com/job1
+                  - label: GIT commit
+                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                gradleEnterpriseSettings:
+                  backgroundPublicationEnabled: true
+                  buildOutputCapturingEnabled: true
+                  taskInputsFileCapturingEnabled: true
+                  testOutputCapturingEnabled: true
+                buildOptions:
+                  buildCacheEnabled: true
+                  configurationCacheEnabled: true
+                  configurationOnDemandEnabled: true
+                  continuousBuildEnabled: true
+                  continueOnFailureEnabled: true
+                  daemonEnabled: true
+                  dryRunEnabled: true
+                  fileSystemWatchingEnabled: true
+                  maxNumberOfGradleWorkers: 4
+                  offlineModeEnabled: true
+                  parallelProjectExecutionEnabled: true
+                  refreshDependenciesEnabled: true
+                  rerunTasksEnabled: true
+                environment:
+                  username: gradle
+                  operatingSystem: macOS 12.2.1 (x86_64)
+                  numberOfCpuCores: 16
+                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
+                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
+                  jvmMaxMemoryHeapSize: 16777216
+                  jvmCharset: UTF-8
+                  jvmLocale: English (United States)
+                  publicHostname: agent.gradle.com
+                  localHostname: gradle
+                  localIpAddresses:
+                    - 192.168.1.126
+                    - 192.168.1.128
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-attributes:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenAttributes
+      summary: Get the attributes of a Maven Build Scan.
+      description: >-
+        This model is Maven specific and cannot be requested for another build
+        tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The attributes of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenAttributes'
+              example:
+                id: 9r4d13f0r3v3r
+                buildStartTime: 1637316480
+                buildDuration: 11000
+                mavenVersion: 3.8.4
+                extensionVersion: 1.11.1
+                topLevelProjectName: example-project
+                requestedGoals:
+                  - clean
+                  - verify
+                hasFailed: false
+                tags:
+                  - CI
+                  - feature-branch
+                values:
+                  - name: branch
+                    value: feature/one
+                  - name: commitId
+                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                links:
+                  - label: CI job
+                    url: https://ci.com/job1
+                  - label: GIT commit
+                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                gradleEnterpriseSettings:
+                  backgroundPublicationEnabled: true
+                  buildOutputCapturingEnabled: true
+                  goalInputsFileCapturingEnabled: true
+                  testOutputCapturingEnabled: true
+                buildOptions:
+                  batchModeEnabled: true
+                  debugEnabled: true
+                  errorsEnabled: true
+                  failAtEndEnabled: true
+                  failFastEnabled: true
+                  failNeverEnabled: true
+                  laxChecksumsEnabled: true
+                  maxNumberOfThreads: 4
+                  nonRecursiveEnabled: true
+                  noSnapshotsUpdatesEnabled: true
+                  offlineModeEnabled: true
+                  quietEnabled: true
+                  rerunGoals: false
+                  strictChecksumsEnabled: true
+                  updateSnapshotsEnabled: true
+                environment:
+                  username: maven
+                  operatingSystem: macOS 12.2.1 (x86_64)
+                  numberOfCpuCores: 16
+                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
+                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
+                  jvmMaxMemoryHeapSize: 16777216
+                  jvmCharset: UTF-8
+                  jvmLocale: English (United States)
+                  publicHostname: agent.gradle.com
+                  localHostname: maven
+                  localIpAddresses:
+                    - 192.168.1.126
+                    - 192.168.1.128
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-build-cache-performance:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleBuildCachePerformance
+      summary: Get the build cache performance of a Gradle Build Scan.
+      description: >-
+        This model is Gradle specific and cannot be requested for another build
+        tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The build cache performance of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleBuildCachePerformance'
+              example:
+                id: 9r4d13f0r3v3r
+                buildTime: 5000
+                effectiveTaskExecutionTime: 5000
+                serialTaskExecutionTime: 10000
+                serializationFactor: 2
+                taskExecution:
+                  - taskPath: ':task'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: avoided_from_local_cache
+                    duration: 5000
+                    fingerprintingDuration: 5
+                    avoidanceSavings: 6000
+                  - taskPath: ':task2'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: avoided_from_remote_cache
+                    duration: 3000
+                    fingerprintingDuration: 3
+                    avoidanceSavings: 4000
+                  - taskPath: ':task3'
+                    avoidanceOutcome: executed_not_cacheable
+                    duration: 2000
+                    fingerprintingDuration: 6
+                    nonCacheabilityCategory: cache-if_condition_not_matched
+                    nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
+                taskFingerprintingSummary:
+                  count: 1
+                  serialDuration: 8
+                avoidanceSavingsSummary:
+                  total: 10000
+                  ratio: 0.55556
+                  upToDate: 0
+                  localBuildCache: 6000
+                  remoteBuildCache: 4000
+                buildCaches:
+                  local:
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  remote:
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  overhead:
+                    uploading: 100
+                    downloading: 200
+                    packing: 50
+                    unpacking: 25
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-build-cache-performance:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenBuildCachePerformance
+      summary: Get the build cache performance of a Maven Build Scan.
+      description: >-
+        This model is Maven specific and cannot be requested for another build
+        tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The build cache performance of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenBuildCachePerformance'
+              example:
+                id: 9r4d13f0r3v3r
+                buildTime: 5000
+                effectiveProjectExecutionTime: 5000
+                serialProjectExecutionTime: 10000
+                serializationFactor: 2
+                goalExecution:
+                  - goalName: clean:clean
+                    goalExecutionId: default-clean
+                    goalProjectName: myproject
+                    avoidanceOutcome: executed_not_cacheable
+                    duration: 2000
+                    nonCacheabilityCategory: build_cache_disabled_by_user
+                    nonCacheabilityReason: >-
+                      Neither the local or remote build cache were enabled in
+                      the configuration of the build.
+                  - goalName: compiler:compile
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
+                    goalExecutionId: default-compile
+                    goalProjectName: myproject
+                    avoidanceOutcome: avoided_from_local_cache
+                    duration: 5000
+                    fingerprintingDuration: 5
+                    avoidanceSavings: 6000
+                  - goalName: compiler:compile
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
+                    goalExecutionId: default-compile
+                    goalProjectName: myproject2
+                    avoidanceOutcome: avoided_from_remote_cache
+                    duration: 3000
+                    fingerprintingDuration: 3
+                    avoidanceSavings: 4000
+                goalFingerprintingSummary:
+                  count: 1
+                  serialDuration: 8
+                avoidanceSavingsSummary:
+                  total: 10000
+                  ratio: 0.55556
+                  localBuildCache: 6000
+                  remoteBuildCache: 4000
+                buildCaches:
+                  local:
+                    isEnabled: true
+                    isDisabledDueToError: false
+                  remote:
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  overhead:
+                    uploading: 100
+                    downloading: 200
+                    packing: 50
+                    unpacking: 25
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/build-cache/nodes/{name}:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: >-
+          The name of the Build Cache Node. To select the Built-in Build Cache
+          Node, use `Built-in` as name.
+    get:
+      operationId: GetBuildCacheNode
+      summary: View the configuration of a Build Cache Node.
+      description: >-
+        View the enablement status and replication configuration of a Build
+        Cache Node.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The configuration of a Build Cache Node.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/NodeConfiguration'
+              example:
+                enabled: false
+                replication:
+                  source: parent-node-1
+                  preemptive: true
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+    put:
+      operationId: CreateOrUpdateBuildCacheNode
+      summary: Create or update a Build Cache Node.
+      description: >
+        Create a new Build Cache Node in Gradle Enterprise or update the
+        configuration of an existing one.
+
+        The Built-in Build Cache Node cannot be named as the target of this
+        operation.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/NodeConfiguration'
+            example:
+              enabled: false
+              replication:
+                source: parent-node-1
+                preemptive: true
+      responses:
+        '200':
+          description: >-
+            The name referenced an existing Build Cache Node and that Build
+            Cache Node’s configuration was updated successfully.
+        '201':
+          description: >-
+            A new Build Cache Node was created with the configuration specified
+            in the request.
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+  /api/build-cache/nodes/{name}/secret:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: The name of the Build Cache Node.
+    post:
+      operationId: RegenerateSecretOfBuildCacheNode
+      summary: Regenerate the secret of a Build Cache Node.
+      description: >
+        Regenerates the secret associated with the named Build Cache Node. The
+        old secret expires immediately, causing the Build Cache Node to
+
+        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot
+        be named as the target of this operation.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '200':
+          description: >-
+            The name referenced an existing Build Cache Node and that Build
+            Cache Node's secret was regenerated.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/KeySecretPair'
+              example:
+                key: cvzxztkqkqxzc3vcruabpcr264
+                secret: e5ag76yp6abcc5jbxusboca313
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+  /api/build-cache/nodes/{name}/purge:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: >-
+          The name of the Build Cache Node. To select the Built-in Build Cache
+          Node, use `Built-in` as name.
+    post:
+      operationId: InitiatePurgeOfBuildCacheNode
+      summary: Deletes all entries from a Build Cache Node.
+      description: >
+        Triggers the deletion of all entries stored at the named Build Cache
+        Node.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '202':
+          description: Purging the Build Cache Node was successfully initiated.
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NodeNotSignedInError'
+components:
+  securitySchemes:
+    GradleEnterpriseAccessKey:
+      type: http
+      in: header
+      scheme: bearer
+      bearerFormat: Bearer <<Gradle Enterprise Access Key>>
+      description: >
+        All requests require a Gradle Enterprise access key as a bearer token. 
+
+        Given an access key of
+        `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required
+        header is `Authorization: Bearer
+        l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
+
+
+        Please consult the [Gradle Enterprise API User
+        Manual](https://docs.gradle.com/api-manual#access_control) for guidance
+        on how to provision access keys and check user permissions.
+  responses:
+    BadRequestError:
+      description: The request cannot be fulfilled due to a problem.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            BuildDeletedProblemResponse:
+              $ref: '#/components/examples/BuildDeletedApiProblemExample'
+            NonApplicableModelProblemResponse:
+              $ref: '#/components/examples/NonApplicableModelApiProblemExample'
+            RequestValidationApiProblemResponse:
+              $ref: '#/components/examples/RequestValidationApiProblemExample'
+    NotFoundError:
+      description: >-
+        The referenced resource either does not exist or the permissions to know
+        about it are missing.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            NotFoundResponse:
+              $ref: '#/components/examples/NotFoundApiProblemExample'
+    UnexpectedError:
+      description: The server encountered an unexpected error.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            UnexpectedErrorResponse:
+              $ref: '#/components/examples/UnexpectedErrorApiProblemExample'
+    NotReadyError:
+      description: The server is not ready to handle the request.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            IngestionNotCompletedResponse:
+              $ref: '#/components/examples/IngestionNotCompletedApiProblemExample'
+    NodeNotSignedInError:
+      description: The node was not signed in with Gradle Enterprise.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            NodeNotSignedInResponse:
+              $ref: '#/components/examples/NodeNotSignedInProblemExample'
+  schemas:
+    ApiProblem:
+      type: object
+      description: >
+        Response detailing why a request was rejected.
+
+        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807)
+        standard (colloquially known as "Problem JSON") for the response format.
+      required:
+        - type
+        - title
+        - status
+      properties:
+        status:
+          type: integer
+          description: HTTP status code of the problem response.
+        type:
+          type: string
+          description: A URN (Uniform Resource Name) identifying the type of the problem.
+        title:
+          type: string
+          description: The underlying reason for the problem.
+        detail:
+          type: string
+          description: >-
+            A longer and comprehensive description of the problem. May be `null`
+            if not available.
+          x-nullable: true
+    Build:
+      type: object
+      description: A build with basic attributes of a Build Scan.
+      required:
+        - id
+        - availableAt
+        - buildToolType
+        - buildToolVersion
+        - buildAgentVersion
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        availableAt:
+          type: integer
+          format: int64
+          description: >-
+            The time in milliseconds from the Epoch as of when the Build Scan
+            has been received.
+        buildToolType:
+          type: string
+          description: The build tool type used to caputre the Build Scan.
+        buildToolVersion:
+          type: string
+          description: The build tool version used.
+        buildAgentVersion:
+          type: string
+          description: The build agent version used.
+    Builds:
+      type: array
+      items:
+        $ref: '#/components/schemas/Build'
+      description: List of builds with basic attributes of a Build Scan.
+    BuildQuery:
+      type: object
+      properties:
+        availabilityWaitTimeoutSecs:
+          type: integer
+          minimum: 0
+          description: >-
+            The time in seconds the server should wait for ingestion before
+            returning a wait timeout response.
+    BuildAttributesValue:
+      type: object
+      description: A Build Scan value.
+      required:
+        - name
+      properties:
+        name:
+          type: string
+          description: The name of the Build Scan value.
+        value:
+          type: string
+          description: >-
+            The value of the Build Scan value. May be `null` if the Build Scan
+            value is not set.
+    BuildAttributesLink:
+      type: object
+      description: A Build Scan link.
+      required:
+        - label
+        - url
+      properties:
+        label:
+          type: string
+          description: The label of the Build Scan link.
+        url:
+          type: string
+          description: The url  of the Build Scan link.
+    GradleGradleEnterpriseSettings:
+      type: object
+      description: Settings for Gradle Enterprise.
+      properties:
+        backgroundPublicationEnabled:
+          type: boolean
+          description: >-
+            Whether background Build Scan publication was enabled for the build.
+            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
+            Gradle plugin version is < `3.4`. See
+            https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
+          x-nullable: true
+        buildOutputCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether build logging output capturing was enabled for the build.
+            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
+            Gradle plugin version is < `3.7`. See
+            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          x-nullable: true
+        taskInputsFileCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether task input file snapshots capturing was enabled for the
+            build. May be `null` if Gradle version is < `5.0` or Gradle
+            Enterprise Gradle plugin version is < `2.1`. See
+            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
+          x-nullable: true
+        testOutputCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether test logging output capturing was enabled for the build. May
+            be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle
+            plugin version is < `3.7`. See
+            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          x-nullable: true
+    GradleBuildOptions:
+      type: object
+      description: Gradle build options for this build.
+      required:
+        - configurationOnDemandEnabled
+        - continuousBuildEnabled
+        - continueOnFailureEnabled
+        - daemonEnabled
+        - dryRunEnabled
+        - maxNumberOfGradleWorkers
+        - offlineModeEnabled
+        - parallelProjectExecutionEnabled
+        - refreshDependenciesEnabled
+        - rerunTasksEnabled
+      properties:
+        buildCacheEnabled:
+          type: boolean
+          description: >-
+            Whether the build cache was enabled for the build. May be `null` if
+            Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version
+            is < `1.3`. See
+            https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
+          x-nullable: true
+        configurationCacheEnabled:
+          type: boolean
+          description: >-
+            Whether the configuration cache was enabled for the build. May be
+            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
+            plugin version is < `3.4`. See
+            https://docs.gradle.org/current/userguide/configuration_cache.html.
+          x-nullable: true
+        configurationOnDemandEnabled:
+          type: boolean
+          description: >-
+            Whether configuration on demand mode was enabled for the build. See
+            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
+        continuousBuildEnabled:
+          type: boolean
+          description: >-
+            Whether continuous build mode was running for the build. See
+            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
+        continueOnFailureEnabled:
+          type: boolean
+          description: >-
+            Whether continue on failure mode was set for the build. See
+            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
+        daemonEnabled:
+          type: boolean
+          description: >-
+            Whether the build was run with the Gradle Daemon. See
+            https://docs.gradle.org/current/userguide/gradle_daemon.html.
+        dryRunEnabled:
+          type: boolean
+          description: >-
+            Whether the dry run flag was set for the build. See
+            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
+        fileSystemWatchingEnabled:
+          type: boolean
+          description: >-
+            Whether file system watching was enabled for the build. May be
+            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
+            plugin version is < `3.4`. See
+            https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:daemon_watch_fs.
+          x-nullable: true
+        maxNumberOfGradleWorkers:
+          type: integer
+          description: >-
+            The maximum number of build workers used to run the build. See
+            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
+        offlineModeEnabled:
+          type: boolean
+          description: >-
+            Whether the offline mode was set for the build. See
+            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
+        parallelProjectExecutionEnabled:
+          type: boolean
+          description: >-
+            Whether parallel project execution was enabled for the build. See
+            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
+        refreshDependenciesEnabled:
+          type: boolean
+          description: >-
+            Whether the build was set to refresh all dependencies in the
+            dependency cache. See
+            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
+        rerunTasksEnabled:
+          type: boolean
+          description: >-
+            Whether the build was forced to run all the tasks, ignoring any
+            up-to-date checks.
+            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
+    BuildAttributesEnvironment:
+      type: object
+      description: The environment where the build has been executed.
+      required:
+        - operatingSystem
+        - numberOfCpuCores
+        - jreVersion
+        - jvmVersion
+        - jvmMaxMemoryHeapSize
+        - jvmLocale
+      properties:
+        username:
+          type: string
+          description: >-
+            Operating system username of the build user. May be `null` if no
+            username was captured.
+          x-nullable: true
+        operatingSystem:
+          type: string
+          description: Operating system of the build machine.
+        numberOfCpuCores:
+          type: integer
+          description: Number of cores available to the build JVM.
+        jreVersion:
+          type: string
+          description: Version of the Java runtime that executed the build.
+        jvmVersion:
+          type: string
+          description: Version of the Java Virtual Machine that executed the build.
+        jvmMaxMemoryHeapSize:
+          type: integer
+          format: int64
+          description: Maximum heap memory available to the build JVM in bytes.
+        jvmCharset:
+          type: string
+          description: >-
+            The default charset of the JVM that executed the build. May be
+            `null` if capturing was not possible.
+          x-nullable: true
+        jvmLocale:
+          type: string
+          description: The locale of the JVM that executed the build.
+        publicHostname:
+          type: string
+          description: >-
+            The hostname of the build machine, as seen on the network. May be
+            `null` if capturing was not possible.
+          x-nullable: true
+        localHostname:
+          type: string
+          description: >-
+            The hostname of the build machine, as specified by itself. May be
+            `null` if capturing was not possible.
+          x-nullable: true
+        localIpAddresses:
+          type: array
+          items:
+            type: string
+          description: >-
+            The local IP addresses of the build machine. May be `null` if
+            capturing was not possible.
+          x-nullable: true
+    GradleAttributes:
+      type: object
+      description: The attributes of a Gradle Build Scan.
+      required:
+        - id
+        - buildStartTime
+        - buildDuration
+        - gradleVersion
+        - pluginVersion
+        - requestedTasks
+        - hasFailed
+        - tags
+        - values
+        - links
+        - gradleEnterpriseSettings
+        - buildOptions
+        - environment
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildStartTime:
+          type: integer
+          format: int64
+          description: The time when the build started, as milliseconds since Epoch.
+        buildDuration:
+          type: integer
+          format: int64
+          description: The duration of the build, as milliseconds since Epoch.
+        gradleVersion:
+          type: string
+          description: The Gradle version used.
+        pluginVersion:
+          type: string
+          description: The Gradle Enterprise Gradle plugin version used.
+        rootProjectName:
+          type: string
+          description: >-
+            The root project name. May be `null` in case of very early build
+            failure.
+          x-nullable: true
+        requestedTasks:
+          type: array
+          items:
+            type: string
+          description: The list of requested tasks.
+        hasFailed:
+          type: boolean
+          description: True when the build failed, false otherwise.
+        tags:
+          type: array
+          items:
+            type: string
+          description: The list of Build Scan tags.
+        values:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesValue'
+          description: The list of Build Scan values.
+        links:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesLink'
+          description: The list of Build Scan links.
+        gradleEnterpriseSettings:
+          $ref: '#/components/schemas/GradleGradleEnterpriseSettings'
+        buildOptions:
+          $ref: '#/components/schemas/GradleBuildOptions'
+        environment:
+          $ref: '#/components/schemas/BuildAttributesEnvironment'
+    MavenGradleEnterpriseSettings:
+      type: object
+      description: Settings for Gradle Enterprise.
+      properties:
+        backgroundPublicationEnabled:
+          type: boolean
+          description: >-
+            Whether background Build Scan publication was enabled for the build.
+            May be `null` if Gradle Enterprise Maven extension version is <
+            `1.6`. See
+            https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
+          x-nullable: true
+        buildOutputCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether to capture build logging output for the build. May be `null`
+            if Gradle Enterprise Maven extension version is < `1.11`. See
+            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          x-nullable: true
+        goalInputsFileCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether to capture goal input file snapshots for the build. May be
+            `null` if Gradle Enterprise Maven extension version is < `1.1`. See
+            https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
+          x-nullable: true
+        testOutputCapturingEnabled:
+          type: boolean
+          description: >-
+            Whether to capture test logging output for the build. May be `null`
+            if Gradle Enterprise Maven extension version is < `1.11`. See
+            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          x-nullable: true
+    MavenBuildOptions:
+      type: object
+      description: Maven build options for this build.
+      required:
+        - errorsEnabled
+        - maxNumberOfThreads
+        - nonRecursiveEnabled
+        - noSnapshotsUpdatesEnabled
+        - offlineModeEnabled
+        - updateSnapshotsEnabled
+      properties:
+        batchModeEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to run in non-interactive (batch)
+            mode. May be `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
+          x-nullable: true
+        debugEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to produce execution debug output.
+            May be `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
+          x-nullable: true
+        errorsEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to produce execution error
+            messages. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
+        failAtEndEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to only fail at the end. May be
+            `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
+          x-nullable: true
+        failFastEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to fail at the first error. May be
+            `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
+          x-nullable: true
+        failNeverEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to never fail, regardless of errors
+            produced. May be `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
+          x-nullable: true
+        laxChecksumsEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to only warn if checksums don't
+            match. May be `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
+          x-nullable: true
+        maxNumberOfThreads:
+          type: integer
+          description: >-
+            Maximum number of threads used when executing the build. See
+            https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
+        nonRecursiveEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to not recurse into sub-projects.
+            See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
+        rerunGoals:
+          type: boolean
+          description: >-
+            Whether the build was configured to rerun goals without checking the
+            build cache. May be `null` if Gradle Enterprise Maven extension
+            version is < `1.13`. See
+            https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
+          x-nullable: true
+        noSnapshotsUpdatesEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to suppress snapshot updates. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
+        offlineModeEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to run offline. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
+        quietEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to run in quiet mode. May be `null`
+            if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
+          x-nullable: true
+        strictChecksumsEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to fail if checksums don't match.
+            May be `null` if capturing was not possible. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
+          x-nullable: true
+        updateSnapshotsEnabled:
+          type: boolean
+          description: >-
+            Whether the build was configured to force a check for missing
+            releases and updated snapshots on remote repositories. See
+            https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
+    MavenAttributes:
+      type: object
+      description: The attributes of a Maven Build Scan.
+      required:
+        - id
+        - buildStartTime
+        - buildDuration
+        - mavenVersion
+        - extensionVersion
+        - requestedGoals
+        - hasFailed
+        - tags
+        - values
+        - links
+        - gradleEnterpriseSettings
+        - buildOptions
+        - environment
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildStartTime:
+          type: integer
+          format: int64
+          description: The time when the build started, as milliseconds since Epoch.
+        buildDuration:
+          type: integer
+          format: int64
+          description: The duration of the build, as milliseconds since Epoch.
+        mavenVersion:
+          type: string
+          description: The Maven version used.
+        extensionVersion:
+          type: string
+          description: The Gradle Enterprise Maven extension version used.
+        topLevelProjectName:
+          type: string
+          description: >-
+            The top level project name. May be `null` in case of very early
+            build failure.
+          x-nullable: true
+        requestedGoals:
+          type: array
+          items:
+            type: string
+          description: The list of requested goals.
+        hasFailed:
+          type: boolean
+          description: True when the build failed, false otherwise.
+        tags:
+          type: array
+          items:
+            type: string
+          description: The list of Build Scan tags.
+        values:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesValue'
+          description: The list of Build Scan values.
+        links:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesLink'
+          description: The list of Build Scan links.
+        gradleEnterpriseSettings:
+          $ref: '#/components/schemas/MavenGradleEnterpriseSettings'
+        buildOptions:
+          $ref: '#/components/schemas/MavenBuildOptions'
+        environment:
+          $ref: '#/components/schemas/BuildAttributesEnvironment'
+    GradleBuildCachePerformanceTaskExecutionEntry:
+      type: object
+      required:
+        - taskPath
+        - avoidanceOutcome
+        - duration
+      properties:
+        taskPath:
+          type: string
+          description: The full task path.
+        taskType:
+          type: string
+          description: The fully qualified class name of the task.
+        avoidanceOutcome:
+          type: string
+          enum:
+            - avoided_up_to_date
+            - avoided_from_local_cache
+            - avoided_from_remote_cache
+            - executed_cacheable
+            - executed_not_cacheable
+            - executed_unknown_cacheability
+            - lifecycle
+            - no-source
+            - skipped
+          description: |
+            The avoidance outcome of this task with respect to performance:
+              * `avoided_up_to_date` - Task whose execution was avoided due to build incrementalism
+              * `avoided_from_local_cache` - Task whose execution was avoided due to reusing a local build cache entry
+              * `avoided_from_remote_cache` - Task whose execution was avoided due to reusing a remote build cache entry
+              * `executed_cacheable` - Task which was executed but was cacheable
+              * `executed_not_cacheable` - Task which was executed but was not cacheable
+              * `executed_unknown_cacheability` - Task which was executed and whose cacheability could not be determined
+              * `lifecycle` - Lifecycle task
+              * `no-source` - No-source task
+              * `skipped` - Skipped task
+        duration:
+          type: integer
+          format: int64
+          description: The task duration in milliseconds.
+        fingerprintingDuration:
+          type: integer
+          format: int64
+          description: >-
+            The task fingerprinting duration in milliseconds. This duration is
+            part of the complete task execution duration. May be `null` if the
+            task was not fingerprinted, or the information was not available.
+          x-nullable: true
+        avoidanceSavings:
+          type: integer
+          format: int64
+          description: >-
+            The task avoidance savings in milliseconds, which can be negative.
+            Negative values indicate that it took more time to reuse outputs
+            than it did to create them originally. May be `null` if the
+            information was not available.
+          x-nullable: true
+        nonCacheabilityCategory:
+          type: string
+          enum:
+            - build_cache_not_enabled
+            - cache-if_condition_not_matched
+            - disabled_to_ensure_correctness
+            - do-not-cache-if_condition_matched
+            - multiple_outputs_declared
+            - no_outputs_declared
+            - non_cacheable_inputs
+            - non_cacheable_task_action
+            - non_cacheable_task_implementation
+            - non_cacheable_tree_output
+            - overlapping_outputs
+            - task_has_no_actions
+            - task_output_caching_not_enabled
+            - unknown
+          description: >
+            The category of the non-cacheability reason:
+              * `build_cache_not_enabled` - Caching has not been enabled for the build
+              * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
+              * `disabled_to_ensure_correctness` - The task failed validation. Available since Gradle 7.0
+              * `do-not-cache-if_condition_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#doNotCacheIf`
+              * `multiple_outputs_declared` - The task declared multiple outputs
+              * `no_outputs_declared` - The task had no outputs declared
+              * `non_cacheable_inputs` - One of the task inputs was not cacheable, either because some type used as an input to the task was loaded via a custom classloader, or a Java lambda was used as an input. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_task_action` - One of the task actions was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_task_implementation` - The task implementation was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_tree_output` - The task had a `org.gradle.api.file.FileTree` or a `org.gradle.api.internal.file.collections.DirectoryFileTree` as an output. Available since Gradle 5.0
+              * `overlapping_outputs` - The tasks outputs overlapped with another task. As Gradle cannot safely determine which task each output file belongs to, it disabled caching            
+              * `task_has_no_actions` - The task did not declare any actions
+              * `task_output_caching_not_enabled` - Caching has not been enabled for the task
+              * `unknown` - Reason for disabled caching was not known
+
+            May be `null` when the task was cacheable or if the information was
+            not available.
+          x-nullable: true
+        nonCacheabilityReason:
+          type: string
+          description: >-
+            The human-readable reason for a non-cacheable task. May be `null`
+            when the task was cacheable or if the information was not available.
+          x-nullable: true
+    GradleBuildCachePerformanceTaskExecution:
+      type: array
+      description: A list of executed tasks with performance related information.
+      items:
+        $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
+    GradleBuildCachePerformanceTaskFingerprintingSummary:
+      type: object
+      description: >-
+        A summary of task fingerprinting. Fingerprinted tasks are part of the
+        `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or
+        `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version
+        is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
+      x-nullable: true
+      required:
+        - count
+        - serialDuration
+      properties:
+        count:
+          type: integer
+          description: Count of fingerprinted tasks.
+        serialDuration:
+          type: integer
+          format: int64
+          description: >-
+            Sum of all fingerprinting times of fingerprinted tasks in
+            milliseconds.
+    GradleBuildCachePerformanceAvoidanceSavingsSummary:
+      type: object
+      description: A breakdown of avoidance savings.
+      required:
+        - total
+        - ratio
+        - upToDate
+        - localBuildCache
+        - remoteBuildCache
+      properties:
+        total:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the tasks due to
+            their outputs being reused in milliseconds.
+        ratio:
+          type: number
+          format: double
+          description: >-
+            The ratio of the total avoidance savings against the potential
+            serial execution time (which is the actual serial execution time
+            plus the total avoidance savings). Quantifies the effect of
+            avoidance savings in this build. The bigger the ratio is, the more
+            time was saved when running the build.
+        upToDate:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the tasks due to
+            build incrementalism in milliseconds.
+        localBuildCache:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the tasks due to
+            their outputs being reused from the local build cache in
+            milliseconds.
+        remoteBuildCache:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the tasks due to
+            their outputs being reused from the remote build cache in
+            milliseconds.
+    GradleBuildCachePerformanceBuildCacheLocalInfo:
+      type: object
+      description: Information about the local build cache used in the build.
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the local build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: >-
+            Whether pushing to the local build cache was enabled.  May be `null`
+            if the local build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: >-
+            Whether the local cache was disabled due to an error occuring in
+            loading or storing local build cache entries.
+        directory:
+          type: string
+          description: >-
+            Location of the local build cache. Can be relative or absolute
+            depending on its value. May be `null` if the local build cache is
+            disabled.
+          x-nullable: true
+    GradleBuildCachePerformanceBuildCacheRemoteInfo:
+      type: object
+      description: Information about the remote build cache used in the build.
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the remote build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: >-
+            Whether pushing to the remote build cache was enabled. May be `null`
+            if the remote build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: >-
+            Wether the remote build cache was disabled during the build due to
+            an error occuring in loading or storing remote build cache entries.
+        url:
+          type: string
+          description: >-
+            URL of the remote build cache. May be `null` if the remote build
+            cache is disabled.
+          x-nullable: true
+    GradleBuildCachePerformanceBuildCacheOverhead:
+      type: object
+      description: Information about the build cache overhead in this build.
+      required:
+        - uploading
+        - downloading
+        - packing
+        - unpacking
+      properties:
+        uploading:
+          type: integer
+          format: int64
+          description: Overhead of upload operations in milliseconds.
+        downloading:
+          type: integer
+          format: int64
+          description: Overhead of download operations in milliseconds.
+        packing:
+          type: integer
+          format: int64
+          description: Overhead of pack operations in milliseconds.
+        unpacking:
+          type: integer
+          format: int64
+          description: Overhead of unpack operations in milliseconds.
+    GradleBuildCachePerformanceBuildCaches:
+      type: object
+      description: >-
+        Information about the local and remote build caches used in the build.
+        May be `null` if the build cache is globally disabled.
+      x-nullable: true
+      required:
+        - local
+        - remote
+        - overhead
+      properties:
+        local:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheLocalInfo'
+        remote:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheRemoteInfo'
+        overhead:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheOverhead'
+    GradleBuildCachePerformance:
+      type: object
+      description: The build cache performance of a Gradle Build Scan.
+      required:
+        - id
+        - buildTime
+        - effectiveTaskExecutionTime
+        - serialTaskExecutionTime
+        - serializationFactor
+        - taskExecution
+        - avoidanceSavingsSummary
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildTime:
+          type: integer
+          format: int64
+          description: Wall clock duration of the build in milliseconds.
+        effectiveTaskExecutionTime:
+          type: integer
+          format: int64
+          description: >-
+            Wall clock time spent executing tasks in milliseconds. It is the
+            time spent between the start of the first task in the execution
+            phase and the end of the last task of the execution phase, removing
+            any interval where no task is being executed.
+        serialTaskExecutionTime:
+          type: integer
+          format: int64
+          description: >-
+            Wall clock time of all task executions in milliseconds. It is the
+            sum of all individual task durations.
+        serializationFactor:
+          type: number
+          format: double
+          description: >-
+            The ratio of `serialTaskExecutionTime` over the
+            `effectiveTaskExecutionTime`. Quantifies the effect of task
+            parallelization. A value equal to `1` means that no parallelization
+            occurred. A value greater than `1` means that tasks were executed
+            faster due to parallelization.
+        taskExecution:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
+        taskFingerprintingSummary:
+          $ref: >-
+            #/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary
+        avoidanceSavingsSummary:
+          $ref: >-
+            #/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary
+        buildCaches:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
+    MavenBuildCachePerformanceGoalExecutionEntry:
+      type: object
+      required:
+        - goalName
+        - mojoType
+        - goalExecutionId
+        - goalProjectName
+        - avoidanceOutcome
+        - duration
+      properties:
+        goalName:
+          type: string
+          description: The goal name.
+        mojoType:
+          type: string
+          description: >-
+            The fully qualified class name of the Mojo that provides the
+            implementation of this goal.
+        goalExecutionId:
+          type: string
+          description: The goal execution ID.
+        goalProjectName:
+          type: string
+          description: The goal project name.
+        avoidanceOutcome:
+          type: string
+          enum:
+            - avoided_from_local_cache
+            - avoided_from_remote_cache
+            - executed_cacheable
+            - executed_not_cacheable
+            - executed_unknown_cacheability
+            - skipped
+          description: |
+            The avoidance outcome of this task with respect to performance:
+              * `avoided_from_local_cache` - Goal whose execution was avoided due to reusing a local build cache entry
+              * `avoided_from_remote_cache` - Goal whose execution was avoided due to reusing a remote build cache entry
+              * `executed_cacheable` - Goal which was executed but was cacheable
+              * `executed_not_cacheable` - Goal which was executed but was not cacheable
+              * `executed_unknown_cacheability` - Goal which was executed and whose cacheability could not be determined
+              * `skipped` - Skipped goal
+        duration:
+          type: integer
+          format: int64
+          description: The goal duration in milliseconds.
+        fingerprintingDuration:
+          type: integer
+          format: int64
+          description: >-
+            The goal fingerprinting duration in milliseconds. This duration is
+            part of the complete task execution duration. May be `null` if the
+            goal was not fingerprinted.
+          x-nullable: true
+        avoidanceSavings:
+          type: integer
+          format: int64
+          description: >-
+            The goal avoidance savings in milliseconds, which can be negative.
+            Negative values indicate that it took more time to reuse outputs
+            than it did to create them originally. May be `null` if the
+            information was not available.
+          x-nullable: true
+        nonCacheabilityCategory:
+          type: string
+          enum:
+            - build_cache_disabled_by_user
+            - goal_execution_marked_non_cacheable
+            - goal_not_supported
+            - no_gradle_enterprise_server_configured
+            - non_clean_build
+            - not_entitled
+            - offline_build
+            - unknown
+            - unknown_entitlements
+          description: >
+            The category of the non-cacheability reason:
+              * `build_cache_disabled_by_user` - The build cache was disabled by the user
+              * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
+              * `goal_not_supported` - The goal did not support build caching
+              * `no_gradle_enterprise_server_configured` - No Gradle Enterprise server was configured
+              * `non_clean_build` - The `clean` lifecycle was not executed 
+              * `not_entitled` - The Gradle Enterprise license entitlements did not allow Maven build caching
+              * `offline_build` - The build was run in offline mode
+              * `unknown` - Reason for disabled caching was not known
+              * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
+
+            May be `null` when the goal execution was cacheable or if the
+            information was not available.
+          x-nullable: true
+        nonCacheabilityReason:
+          type: string
+          description: >-
+            The human-readable reason for a non-cacheable goal execution. May be
+            `null` when the goal execution was cacheable or if the information
+            was not available.
+          x-nullable: true
+    MavenBuildCachePerformanceGoalExecution:
+      type: array
+      description: A list of executed goals with performance related information.
+      items:
+        $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
+    MavenBuildCachePerformanceGoalFingerprintingSummary:
+      type: object
+      description: >-
+        A summary of goal fingerprinting. Fingerprinted goals are part of the
+        `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
+      required:
+        - count
+        - serialDuration
+      properties:
+        count:
+          type: integer
+          description: Count of fingerprinted goals.
+        serialDuration:
+          type: integer
+          format: int64
+          description: >-
+            Sum of all fingerprinting times of fingerprinted goals in
+            milliseconds.
+    MavenBuildCachePerformanceAvoidanceSavingsSummary:
+      type: object
+      description: A breakdown of avoidance savings.
+      required:
+        - total
+        - ratio
+        - localBuildCache
+        - remoteBuildCache
+      properties:
+        total:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the goals due to
+            their outputs being reused in milliseconds.
+        ratio:
+          type: number
+          format: double
+          description: >-
+            The ratio of the total avoidance savings against the potential
+            serial execution time (which is the actual serial execution time
+            plus the total avoidance savings). Quantifies the effect of
+            avoidance savings in this build. The bigger the ratio is, the more
+            time was saved when running the build.
+        localBuildCache:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the goals due to
+            their outputs being reused from the local build cache in
+            milliseconds.
+        remoteBuildCache:
+          type: integer
+          format: int64
+          description: >-
+            The estimated reduction in serial execution time of the goals due to
+            their outputs being reused from the remote build cache in
+            milliseconds.
+    MavenBuildCachePerformanceBuildCacheLocalInfo:
+      type: object
+      description: >-
+        Information about the local build cache used in the build, if it was
+        configured in the build. May be `null` if the local build cache is not
+        configured.
+      x-nullable: true
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the local build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: >-
+            Whether pushing to the local build cache was enabled. May be `null`
+            if the local build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: >-
+            Whether the local cache was disabled due to an error occuring in
+            loading or storing local build cache entries.
+        directory:
+          type: string
+          description: >-
+            Location of the local build cache. Can be relative or absolute
+            depending on its value. May be `null` if the local build cache is
+            disabled.
+          x-nullable: true
+    MavenBuildCachePerformanceBuildCacheRemoteInfo:
+      type: object
+      description: >-
+        Information about the remote build cache used in the build, if it was
+        configured in the build. May be `null` if the remote build cache is not
+        configured.
+      x-nullable: true
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the remote build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: >-
+            Whether pushing to the remote build cache was enabled. May be `null`
+            if the remote build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: >-
+            Whether the remote build cache was disabled during the build due to
+            an error occuring in loading or storing remote build cache entries.
+        url:
+          type: string
+          description: >-
+            URL of the remote build cache. May be `null` if the remote build
+            cache is disabled.
+          x-nullable: true
+    MavenBuildCachePerformanceBuildCacheOverhead:
+      type: object
+      description: Information about the build cache overhead in this build.
+      required:
+        - uploading
+        - downloading
+        - packing
+        - unpacking
+      properties:
+        uploading:
+          type: integer
+          format: int64
+          description: Overhead of upload operations in milliseconds.
+        downloading:
+          type: integer
+          format: int64
+          description: Overhead of download operations in milliseconds.
+        packing:
+          type: integer
+          format: int64
+          description: Overhead of pack operations in milliseconds.
+        unpacking:
+          type: integer
+          format: int64
+          description: Overhead of unpack operations in milliseconds.
+    MavenBuildCachePerformanceBuildCaches:
+      type: object
+      description: >-
+        Information about the local and remote build caches used in the build,
+        if it was configured in the build. May be `null` if the build cache
+        configuration could not be captured (e.g. very early build failure).
+      x-nullable: true
+      required:
+        - overhead
+      properties:
+        local:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheLocalInfo'
+        remote:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheRemoteInfo'
+        overhead:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheOverhead'
+    MavenBuildCachePerformance:
+      type: object
+      description: The build cache performance of a Maven Build Scan.
+      required:
+        - id
+        - buildTime
+        - effectiveProjectExecutionTime
+        - serialProjectExecutionTime
+        - serializationFactor
+        - goalExecution
+        - goalFingerprintingSummary
+        - avoidanceSavingsSummary
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildTime:
+          type: integer
+          format: int64
+          description: Wall clock duration of the build in milliseconds.
+        effectiveProjectExecutionTime:
+          type: integer
+          format: int64
+          description: >-
+            Wall clock time spent executing projects in milliseconds. It is the
+            time spent between the start of the first project execution and the
+            end of the last project execution, removing any interval where no
+            project is being executed.
+        serialProjectExecutionTime:
+          type: integer
+          format: int64
+          description: >-
+            Wall clock time of all project executions in milliseconds. It is the
+            sum of all individual project durations.
+        serializationFactor:
+          type: number
+          format: double
+          description: >-
+            The ratio of `serialProjectExecutionTime` over the
+            `effectiveProjectExecutionTime`. Quantifies the effect of project
+            parallelization. A value equal to `1` means that no parallelization
+            occurred. A value greater than `1` means that projects were executed
+            faster due to parallelization.
+        goalExecution:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
+        goalFingerprintingSummary:
+          $ref: >-
+            #/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary
+        avoidanceSavingsSummary:
+          $ref: >-
+            #/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary
+        buildCaches:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
+    ReplicationConfiguration:
+      description: >-
+        Cached data replication configuration description. May be `null` if
+        replication is not configured.
+      type: object
+      x-nullable: true
+      required:
+        - source
+        - preemptive
+      properties:
+        source:
+          type: string
+          description: The name of the Build Cache Node which is the source of data.
+        preemptive:
+          type: boolean
+          description: Indicates if preemptive replication is enabled from the source.
+    NodeConfiguration:
+      description: A Build Cache Node configuration description.
+      type: object
+      required:
+        - enabled
+      properties:
+        enabled:
+          type: boolean
+          description: Indicates if the Build Cache Node is enabled.
+        replication:
+          $ref: '#/components/schemas/ReplicationConfiguration'
+    KeySecretPair:
+      description: A Build Cache Node key and secret pair.
+      type: object
+      required:
+        - key
+        - secret
+      properties:
+        key:
+          type: string
+          description: A unique identifier for the Build Cache Node in Gradle Enterprise.
+        secret:
+          type: string
+          description: The secret associated with the Build Cache Node.
+  examples:
+    BuildDeletedApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:build-deleted
+        title: Build deleted.
+        detail: |
+          Build 9r4d13f0r3v3r has been deleted and is no longer available.
+        status: 400
+    NonApplicableModelApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:build-model-not-applicable
+        title: Build model is not applicable.
+        detail: >
+          Build model BuildCachePerformance is not available for build
+          9r4d13f0r3v3r because the build agent version is not supported.
+        status: 400
+    RequestValidationApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:validation
+        title: Request validation failed.
+        detail: >
+          Numeric instance is lower than the required minimum (minimum: 1,
+          found: 0) (Additional info: Query parameter: maxWaitSecs).
+        status: 400
+    NotFoundApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:not-found
+        title: >-
+          The requested resource is not found or the permissions to know about
+          it are missing.
+        status: 404
+    UnexpectedErrorApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:unexpected-error
+        title: Encountered an internal server error.
+        detail: |
+          The ingestion of build 9r4d13f0r3v3r failed.
+        status: 500
+    IngestionNotCompletedApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:build-processing-incomplete
+        title: Build processing is incomplete.
+        detail: >
+          The data of build 9r4d13f0r3v3r is not yet available for viewing.
+          Please try again later.
+        status: 503
+    NodeNotSignedInProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:node-not-signed-in
+        title: >-
+          Node with name not-signed-in-node1 must be signed-in before this
+          operation can be performed.
+        status: 503
+tags:
+  - name: Builds
+    description: >
+      Endpoints related to retrieving details of a Build Scan of the Gradle
+      Enterprise instance. 
+
+      To access these endpoints the user requires the `Access build data via the
+      API` permission.
+  - name: BuildCache
+    x-displayName: Build Cache
+    description: >
+      Endpoints related to configuring the Build Cache nodes of the Gradle
+      Enterprise instance. 
+
+      To access these endpoints the user requires the `Configure build caches`
+      permission.
+  - name: GradleEnterprise
+    x-traitTag: true
+    description: All endpoints of the Gradle Enterprise API.
diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index 227452f8..ff225483 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -5,3 +5,10 @@ plugins {
 dependencies {
     api(project(":build-scan-data-loader-api"))
 }
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(8))
+        vendor.set(JvmVendorSpec.AZUL)
+    }
+}
diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
index 227452f8..ff225483 100644
--- a/components/build-scan-data-loader-online/build.gradle.kts
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -5,3 +5,10 @@ plugins {
 dependencies {
     api(project(":build-scan-data-loader-api"))
 }
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(8))
+        vendor.set(JvmVendorSpec.AZUL)
+    }
+}

From d114590ca6b320b296f31e39dce3e1ffd1497175 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Wed, 10 May 2023 16:33:43 +0200
Subject: [PATCH 03/57] Add OpenApi specification for GE 2022.4

---
 .../src/main/openapi/openapi.yaml             | 1522 +++++++++++------
 1 file changed, 1008 insertions(+), 514 deletions(-)

diff --git a/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml b/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
index 0376bafb..8d7bfb30 100644
--- a/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
+++ b/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
@@ -1,10 +1,9 @@
 openapi: 3.0.3
 info:
   title: Gradle Enterprise API
-  description: >
-    The Gradle Enterprise API allows programmatic interaction with various
-    aspects of Gradle Enterprise, from configuration to inspecting build data.
-  version: "2022.2.4"
+  description: |
+    The Gradle Enterprise API allows programmatic interaction with various aspects of Gradle Enterprise, from configuration to inspecting build data.
+  version: "2022.4"
   license:
     name: Gradle Enterprise License
     url: https://gradle.com/legal/gradle-enterprise-software-agreement
@@ -22,20 +21,15 @@ security:
   - GradleEnterpriseAccessKey: []
 paths:
   /api/builds:
-    description: >
-      Returns a list of builds with basic attributes of a Build Scan. The
-      returned list is capped by the `maxBuilds` and `maxWaitSecs` query
-      parameters. This
-
-      endpoint supports pagination by using the `sinceBuild` query parameter,
-      and the last returned build from a previous call to this endpoint, one can
-      get
-
-      the next batch of builds.
+    description: |
+      Returns a list of builds with the common attributes of a Build Scan.
+      The returned list is capped by the `maxBuilds` and `maxWaitSecs` query parameters.
+      This endpoint supports pagination by using the `fromBuild` or `sinceBuild` query parameters, and the last returned build from a previous call to one of these endpoints.
     parameters:
       - in: query
         name: BuildsQuery
         explode: true
+        description: The query parameters used to retrieve the list of builds.
         schema:
           title: BuildsQuery
           type: object
@@ -45,65 +39,84 @@ paths:
               format: int64
               minimum: 0
               x-nullable: true
-              description: >
-                The time in milliseconds from the Epoch as of when the Build
-                Scan has been received. A value of `0` will process all builds.
-                If not provided, the time
-
-                in milliseconds when the request is received by the Gradle
-                Enterprise instance will be used. This parameter has no effect
-                if `sinceBuild` is used.
+              description: |
+                **This parameter is deprecated, use `fromInstant` instead.**
+                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant.
+                This parameter can only be used with `reverse=false`.
+                Therefore, a value of `0` will process all builds.
+                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
+                This parameter has no effect if any of `sinceBuild`, `fromInstant`, `fromBuild` are used.
+              deprecated: true
             sinceBuild:
               type: string
               x-nullable: true
-              description: >
-                A Build Scan ID allowing to retrieve builds for which Gradle
-                Enterprise completed receiving and processing after the given
-                Build Scan ID (excluding it).
-
-                This parameter has precedence over any value set for the `since`
-                parameter. A valid Build Scan ID must be provided, that is, a
-                Build Scan ID that exists
-
-                in the Gradle Enterprise instance. A Build Scan ID for a deleted
-                build is valid.
+              description: |
+                **This parameter is deprecated, use `fromBuild` instead.**
+                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it).
+                This parameter can only be used with `reverse=false`.
+                This parameter has precedence over any value set for the `since` parameter.
+                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
+                A Build Scan ID for a deleted build is valid.
+                This parameter has no effect if any of `fromInstant`, `fromBuild` are used.
+              deprecated: true
+            fromInstant:
+              type: integer
+              format: int64
+              minimum: 0
+              x-nullable: true
+              description: |
+                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant when used in conjunction with `reverse=false`, or before this instant when used in conjunction with `reverse=true`.
+                Therefore, a value of `0` will process all builds.
+                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
+                This parameter has no effect if `fromBuild` is used.
+            fromBuild:
+              type: string
+              x-nullable: true
+              description: |
+                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it) when used in conjunction with `reverse=false`, or before the given Build Scan ID (excluding it) when used in conjunction with `reverse=true`.
+                This parameter has precedence over any value set for the `since`, `sinceBuild`, `fromInstant` parameters.
+                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
+                A Build Scan ID for a deleted build is valid.
+            reverse:
+              type: boolean
+              x-nullable: true
+              description: |
+                A boolean indicating the time direction of the query.
+                A value of `true` indicates a backward query, and returned builds will be sorted from most to least recent.
+                A value of `false` indicates a forward query, and returned builds will be sorted from least to most recent.
+                This parameter has no effect if any of `since`, `sinceBuild` are used.
+                If not provided, the default value is `false`.
             maxBuilds:
               type: integer
               minimum: 0
               maximum: 1000
               x-nullable: true
-              description: >
-                The maximum number of builds returned by the query. The query
-                returns when that number is reached or when `maxWaitSecs` is
-                reached.
-
+              description: |
+                The maximum number of builds returned by the query.
+                The query returns when that number is reached or when `maxWaitSecs` is reached.
                 If not provided, the default value is `100`.
             maxWaitSecs:
               type: integer
               minimum: 1
               maximum: 20
               x-nullable: true
-              description: >
-                The maximum number of seconds to wait for builds before
-                returning. If this time is reached before `maxBuilds` is
-                reached, the query returns with the
-
-                already processed builds. Note that this time is respected with
-                best effort. A query will return soon after this time has passed
-                but there is no 
-
-                guarantee that it exactly returns before this time has passed.
+              description: |
+                The maximum number of seconds to wait for builds before returning.
+                If this time is reached before `maxBuilds` is reached, the query returns with the already processed builds.
+                Note that this time is respected with best effort.
+                A query will return soon after this time has passed but there is no guarantee that it exactly returns before this time has passed.
+                This parameter has no effect if `reverse=true` is specified, because new builds cannot become available in the past.
                 If not provided, the default value is `3`.
     get:
       operationId: GetBuilds
-      summary: Get a list of builds with basic attributes of a Build Scan.
+      summary: Get a list of builds with the common attributes of a Build Scan.
       description: The contained attributes are build tool agnostic.
       tags:
         - Builds
         - GradleEnterprise
       responses:
         '200':
-          description: A list of builds with basic attributes of a Build Scan.
+          description: A list of builds with the common attributes of a Build Scan.
           content:
             application/json:
               schema:
@@ -143,6 +156,7 @@ paths:
       - in: query
         name: BuildQuery
         explode: true
+        description: The query parameters used to retrieve the common attributes of a Build Scan.
         schema:
           $ref: '#/components/schemas/BuildQuery'
     get:
@@ -184,14 +198,13 @@ paths:
       - in: query
         name: BuildQuery
         explode: true
+        description: The query parameters used to retrieve the attributes of a Gradle Build Scan.
         schema:
           $ref: '#/components/schemas/BuildQuery'
     get:
       operationId: GetGradleAttributes
       summary: Get the attributes of a Gradle Build Scan.
-      description: >-
-        This model is Gradle specific and cannot be requested for another build
-        tool.
+      description: This model is Gradle specific and cannot be requested for another build tool.
       tags:
         - Builds
         - GradleEnterprise
@@ -278,14 +291,13 @@ paths:
       - in: query
         name: BuildQuery
         explode: true
+        description: The query parameters used to retrieve the attributes of a Maven Build Scan.
         schema:
           $ref: '#/components/schemas/BuildQuery'
     get:
       operationId: GetMavenAttributes
       summary: Get the attributes of a Maven Build Scan.
-      description: >-
-        This model is Maven specific and cannot be requested for another build
-        tool.
+      description: This model is Maven specific and cannot be requested for another build tool.
       tags:
         - Builds
         - GradleEnterprise
@@ -374,14 +386,13 @@ paths:
       - in: query
         name: BuildQuery
         explode: true
+        description: The query parameters used to retrieve the build cache performance of a Gradle Build Scan.
         schema:
           $ref: '#/components/schemas/BuildQuery'
     get:
       operationId: GetGradleBuildCachePerformance
       summary: Get the build cache performance of a Gradle Build Scan.
-      description: >-
-        This model is Gradle specific and cannot be requested for another build
-        tool.
+      description: This model is Gradle specific and cannot be requested for another build tool.
       tags:
         - Builds
         - GradleEnterprise
@@ -412,11 +423,18 @@ paths:
                     fingerprintingDuration: 3
                     avoidanceSavings: 4000
                   - taskPath: ':task3'
+                    taskType: org.gradle.api.tasks.Task
                     avoidanceOutcome: executed_not_cacheable
                     duration: 2000
                     fingerprintingDuration: 6
                     nonCacheabilityCategory: cache-if_condition_not_matched
                     nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
+                  - taskPath: ':task4'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: skipped
+                    duration: 0
+                    fingerprintingDuration: 0
+                    skipReasonMessage: some skip reason message
                 taskFingerprintingSummary:
                   count: 1
                   serialDuration: 8
@@ -432,6 +450,8 @@ paths:
                     isPushEnabled: true
                     isDisabledDueToError: false
                   remote:
+                    type: HTTP
+                    className: org.example.MyBuildCache
                     isEnabled: true
                     isPushEnabled: true
                     isDisabledDueToError: false
@@ -459,14 +479,13 @@ paths:
       - in: query
         name: BuildQuery
         explode: true
+        description: The query parameters used to retrieve the build cache performance of a Maven Build Scan.
         schema:
           $ref: '#/components/schemas/BuildQuery'
     get:
       operationId: GetMavenBuildCachePerformance
       summary: Get the build cache performance of a Maven Build Scan.
-      description: >-
-        This model is Maven specific and cannot be requested for another build
-        tool.
+      description: This model is Maven specific and cannot be requested for another build tool.
       tags:
         - Builds
         - GradleEnterprise
@@ -485,14 +504,13 @@ paths:
                 serializationFactor: 2
                 goalExecution:
                   - goalName: clean:clean
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
                     goalExecutionId: default-clean
                     goalProjectName: myproject
                     avoidanceOutcome: executed_not_cacheable
                     duration: 2000
                     nonCacheabilityCategory: build_cache_disabled_by_user
-                    nonCacheabilityReason: >-
-                      Neither the local or remote build cache were enabled in
-                      the configuration of the build.
+                    nonCacheabilityReason: Neither the local or remote build cache were enabled in the configuration of the build.
                   - goalName: compiler:compile
                     mojoType: org.apache.maven.plugin.jar.JarMojo
                     goalExecutionId: default-compile
@@ -538,6 +556,109 @@ paths:
           $ref: '#/components/responses/UnexpectedError'
         '503':
           $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-projects:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build structure of a Gradle Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleProjects
+      summary: Get the projects of a Gradle Build Scan.
+      description: This model is Gradle specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The projects of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleProjects'
+              example:
+                - name: root project
+                  path: ':'
+                - name: sub project
+                  path: ':sub'
+                  parent: 0
+                - name: included build root project
+                  path: ':included'
+                - name: included build sub project
+                  path: ':included:sub'
+                  parent: 2
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-modules:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build structure of a Maven Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenModules
+      summary: Get the modules of a Maven Build Scan.
+      description: This model is Maven specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The modules of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenModules'
+              example:
+                - name: top level project
+                  groupId: com
+                  artifactId: top-level
+                  version: '1.0'
+                - name: sub project a
+                  groupId: com
+                  artifactId: sub-a
+                  version: '1.1'
+                  parent: 0
+                - name: sub project b
+                  groupId: com
+                  artifactId: sub-b
+                  version: '2.0'
+                  parent: 0
+                - name: sub project a 2
+                  groupId: com
+                  artifactId: sub-a-a
+                  version: 2.1-SNAPSHOT
+                  parent: 1
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
   /api/build-cache/nodes/{name}:
     parameters:
       - in: path
@@ -545,15 +666,11 @@ paths:
         schema:
           type: string
         required: true
-        description: >-
-          The name of the Build Cache Node. To select the Built-in Build Cache
-          Node, use `Built-in` as name.
+        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
     get:
       operationId: GetBuildCacheNode
       summary: View the configuration of a Build Cache Node.
-      description: >-
-        View the enablement status and replication configuration of a Build
-        Cache Node.
+      description: View the enablement status and replication configuration of a Build Cache Node.
       tags:
         - BuildCache
         - GradleEnterprise
@@ -576,12 +693,9 @@ paths:
     put:
       operationId: CreateOrUpdateBuildCacheNode
       summary: Create or update a Build Cache Node.
-      description: >
-        Create a new Build Cache Node in Gradle Enterprise or update the
-        configuration of an existing one.
-
-        The Built-in Build Cache Node cannot be named as the target of this
-        operation.
+      description: |
+        Create a new Build Cache Node in Gradle Enterprise or update the configuration of an existing one.
+        The Built-in Build Cache Node cannot be named as the target of this operation.
       tags:
         - BuildCache
         - GradleEnterprise
@@ -598,13 +712,9 @@ paths:
                 preemptive: true
       responses:
         '200':
-          description: >-
-            The name referenced an existing Build Cache Node and that Build
-            Cache Node’s configuration was updated successfully.
+          description: The name referenced an existing Build Cache Node and that Build Cache Node’s configuration was updated successfully.
         '201':
-          description: >-
-            A new Build Cache Node was created with the configuration specified
-            in the request.
+          description: A new Build Cache Node was created with the configuration specified in the request.
         '400':
           $ref: '#/components/responses/BadRequestError'
         '404':
@@ -620,20 +730,15 @@ paths:
     post:
       operationId: RegenerateSecretOfBuildCacheNode
       summary: Regenerate the secret of a Build Cache Node.
-      description: >
-        Regenerates the secret associated with the named Build Cache Node. The
-        old secret expires immediately, causing the Build Cache Node to
-
-        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot
-        be named as the target of this operation.
+      description: |
+        Regenerates the secret associated with the named Build Cache Node. The old secret expires immediately, causing the Build Cache Node to
+        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot be named as the target of this operation.
       tags:
         - BuildCache
         - GradleEnterprise
       responses:
         '200':
-          description: >-
-            The name referenced an existing Build Cache Node and that Build
-            Cache Node's secret was regenerated.
+          description: The name referenced an existing Build Cache Node and that Build Cache Node's secret was regenerated.
           content:
             application/json:
               schema:
@@ -652,15 +757,12 @@ paths:
         schema:
           type: string
         required: true
-        description: >-
-          The name of the Build Cache Node. To select the Built-in Build Cache
-          Node, use `Built-in` as name.
+        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
     post:
       operationId: InitiatePurgeOfBuildCacheNode
       summary: Deletes all entries from a Build Cache Node.
-      description: >
-        Triggers the deletion of all entries stored at the named Build Cache
-        Node.
+      description: |
+        Triggers the deletion of all entries stored at the named Build Cache Node.
       tags:
         - BuildCache
         - GradleEnterprise
@@ -673,25 +775,427 @@ paths:
           $ref: '#/components/responses/UnexpectedError'
         '503':
           $ref: '#/components/responses/NodeNotSignedInError'
+  /api/test-distribution/agent-pools:
+    get:
+      operationId: ListTestDistributionAgentPools
+      summary: Lists Agent Pools
+      description: Returns a list of all Agent Pools.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains a listing of all Agent Pools.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolPage'
+              example:
+                content:
+                  - id: m4yfaq4a
+                    name: abc-agents-pool
+                    minimumSize: 10
+                    maximumSize: 20
+                    capabilities:
+                      - os=linux
+                      - jdk=11
+                      - team-abc
+                    orderIndex: 1
+                  - id: dwc4whvi
+                    name: def-agents-pool
+                    minimumSize: 0
+                    maximumSize: 10
+                    capabilities:
+                      - os=windows
+                      - jdk=11
+                    orderIndex: 2
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    post:
+      operationId: CreateTestDistributionAgentPool
+      summary: Create an Agent Pool
+      description: |
+        Create a new Agent Pool in Gradle Enterprise.
+        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
+        When not specified, the Agent Pool will be added last.
+        When specified, the Agent Pool will be added at the specified index and all other Agent Pools will be moved down.
+        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
+            example:
+              name: abc-agents-pool
+              minimumSize: 10
+              maximumSize: 20
+              capabilities:
+                - os=linux
+                - jdk=11
+                - team-abc
+              orderIndex: 1
+      responses:
+        '200':
+          description: A new Agent Pool was created with the configuration specified in the request.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/agent-pools/{poolId}:
+    parameters:
+      - in: path
+        name: poolId
+        example: m4yfaq4a
+        schema:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        required: true
+        description: The ID of the pool to view.
+    get:
+      operationId: GetTestDistributionAgentPool
+      summary: View the properties of an Agent Pool
+      description: View the identifier, capabilities and size of an Agent Pool.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool whose configuration is described in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    put:
+      operationId: CreateOrUpdateTestDistributionAgentPool
+      summary: Create or update an Agent Pool
+      description: |
+        Create a new Agent Pool in Gradle Enterprise or update the configuration of an existing one.
+        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
+        When not specified, the Agent Pool will be either added last on creation, or will not change position on update.
+        When specified, the Agent Pool will be added at/moved to the specified index and all other Agent Pools will be moved down.
+        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
+            example:
+              name: abc-agents-pool
+              minimumSize: 10
+              maximumSize: 20
+              capabilities:
+                - os=linux
+                - jdk=11
+                - team-abc
+              orderIndex: 1
+      responses:
+        '200':
+          description: The Agent Pool was created or its configuration was updated successfully.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    delete:
+      operationId: DeleteTestDistributionAgentPool
+      summary: Delete an Agent Pool
+      description: View the identifier, capabilities and size of an Agent Pool.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool and it was deleted.
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/agent-pools/{poolId}/status:
+    parameters:
+      - in: path
+        name: poolId
+        example: m4yfaq4a
+        schema:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        required: true
+        description: The ID of the pool to view.
+    get:
+      operationId: GetTestDistributionAgentPoolStatus
+      summary: View the status of an Agent Pool
+      description: |
+        View the status of an Agent Pool, such as its current size.
+        To access this endpoint the user requires the `Test Distribution` permission.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool whose status is described in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolStatus'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                connectedAgents: 15
+                idleAgents: 5
+                desiredAgents: 10
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/api-keys:
+    get:
+      operationId: ListTestDistributionApiKeys
+      summary: Lists Test Distribution API keys
+      description: Returns a list of all Test Distribution API key prefixes.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains a listing of the requested type of (active or revoked) Test Distribution API keys.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefixPage'
+              example:
+                content:
+                  - keyPrefix: am3mbm5kamztbmrmygym5kamct
+                    generatedAt: '2021-01-01T12:59:59Z'
+                    lastUsedAt: '2021-05-03T10:11:02Z'
+                  - keyPrefix: yw3zbwjtnwthbxp3ym6ybxlnew
+                    generatedAt: '2021-04-20T13:21:43Z'
+                    revokedAt: '2022-10-12T11:22:33Z'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    post:
+      operationId: GenerateTestDistributionApiKey
+      summary: Generate a new Test Distribution API key
+      description: Generate a new Test Distribution API key to connect agents and query the agent pool API.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: A new API key was successfully generated and contained in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKey'
+              example:
+                key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/api-keys/{keyPrefix}:
+    parameters:
+      - in: path
+        name: keyPrefix
+        example: riux3fkajs6ivtajxbrunelywk
+        schema:
+          type: string
+          minLength: 26
+          maxLength: 26
+          pattern: ^[a-z2-7]{26}$
+        required: true
+        description: The prefix of the Test Distribution API key.
+    get:
+      operationId: GetTestDistributionApiKey
+      summary: Get a Test Distribution API keyPrefix information.
+      description: Returns information about a Test Distribution API keyPrefix.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains information about the requested Test Distribution API keyPrefix.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+              example:
+                keyPrefix: am3mbm5kamztbmrmygym5kamct
+                generatedAt: '2021-01-01T12:59:59Z'
+                lastUsedAt: '2021-05-03T10:11:02Z'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    put:
+      operationId: InsertTestDistributionApiKey
+      summary: Insert a specific Test Distribution API key
+      description: |
+        Inserts a specific Test Distribution API key to connect agents and query the agent pool API.
+        If a key with the same prefix but different key already exists, it will return 400.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionApiKey'
+            example:
+              key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
+      responses:
+        '200':
+          description: The API key was successfully inserted.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+              example:
+                keyPrefix: am3mbm5kamztbmrmygym5kamct
+                generatedAt: '2021-01-01T12:59:59Z'
+                lastUsedAt: '2021-05-03T10:11:02Z'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    delete:
+      operationId: RevokeTestDistributionApiKey
+      summary: Revoke a Test Distribution API key
+      description: |
+        Revoke the Test Distribution API key for the given prefix which uniquely identifies a Test Distribution API key.
+        A revoked key can no longer be used to connect agents, but it will still be queryable and returned in the list.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The API key was revoked successfully.
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/version:
+    get:
+      operationId: GetVersion
+      summary: Provides the version of Gradle Enterprise.
+      description: This endpoint can be accessed by any authenticated user.
+      tags:
+        - Meta
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The version of Gradle Enterprise.
+          content:
+            application/json:
+              schema:
+                title: GradleEnterpriseVersion
+                type: object
+                required:
+                  - string
+                  - year
+                  - release
+                  - patch
+                properties:
+                  string:
+                    type: string
+                    description: The complete version string of format `YEAR.RELEASE.PATCH`, where the patch component is omitted when `0` (e.g. `2022.3`, `2022.3.1`).
+                  year:
+                    type: integer
+                    description: The gregorian calendar year of the release.
+                  release:
+                    type: integer
+                    description: The sequence number of the release for that year, starting with 1.
+                    minimum: 1
+                  patch:
+                    type: integer
+                    description: The patch level of the release, starting with 0.
+                    minimum: 0
+              examples:
+                '2022.3':
+                  value:
+                    string: '2022.3'
+                    year: 2022
+                    release: 3
+                    patch: 0
+                2022.3.1:
+                  value:
+                    string: 2022.3.1
+                    year: 2022
+                    release: 3
+                    patch: 1
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
 components:
   securitySchemes:
     GradleEnterpriseAccessKey:
       type: http
-      in: header
       scheme: bearer
       bearerFormat: Bearer <<Gradle Enterprise Access Key>>
-      description: >
+      description: |
         All requests require a Gradle Enterprise access key as a bearer token. 
+        Given an access key of `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required header is `Authorization: Bearer l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
 
-        Given an access key of
-        `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required
-        header is `Authorization: Bearer
-        l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
-
-
-        Please consult the [Gradle Enterprise API User
-        Manual](https://docs.gradle.com/api-manual#access_control) for guidance
-        on how to provision access keys and check user permissions.
+        Please consult the [Gradle Enterprise API User Manual](https://docs.gradle.com/enterprise/api-manual#access_control) for guidance on how to provision access keys and check user permissions.
   responses:
     BadRequestError:
       description: The request cannot be fulfilled due to a problem.
@@ -700,16 +1204,10 @@ components:
           schema:
             $ref: '#/components/schemas/ApiProblem'
           examples:
-            BuildDeletedProblemResponse:
-              $ref: '#/components/examples/BuildDeletedApiProblemExample'
-            NonApplicableModelProblemResponse:
-              $ref: '#/components/examples/NonApplicableModelApiProblemExample'
             RequestValidationApiProblemResponse:
               $ref: '#/components/examples/RequestValidationApiProblemExample'
     NotFoundError:
-      description: >-
-        The referenced resource either does not exist or the permissions to know
-        about it are missing.
+      description: The referenced resource either does not exist or the permissions to know about it are missing.
       content:
         application/problem+json:
           schema:
@@ -744,14 +1242,32 @@ components:
           examples:
             NodeNotSignedInResponse:
               $ref: '#/components/examples/NodeNotSignedInProblemExample'
+    ForbiddenError:
+      description: The authenticated user has insufficient permissions.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            ForbiddenUserResponse:
+              $ref: '#/components/examples/ForbiddenUserExample'
+    UnauthorizedOrNotFoundError:
+      description: No API key was specified in the request, the key has been revoked or the user bearing the key lacks permissions for this operation.
+    BadRequest:
+      description: The request body is malformed or contains invalid values for at least one of the properties.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            CapabilityValidationProblemResponse:
+              $ref: '#/components/examples/CapabilityValidationProblemExample'
   schemas:
     ApiProblem:
       type: object
-      description: >
+      description: |
         Response detailing why a request was rejected.
-
-        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807)
-        standard (colloquially known as "Problem JSON") for the response format.
+        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807) standard (colloquially known as "Problem JSON") for the response format.
       required:
         - type
         - title
@@ -768,13 +1284,11 @@ components:
           description: The underlying reason for the problem.
         detail:
           type: string
-          description: >-
-            A longer and comprehensive description of the problem. May be `null`
-            if not available.
+          description: A longer and comprehensive description of the problem. May be `null` if not available.
           x-nullable: true
     Build:
       type: object
-      description: A build with basic attributes of a Build Scan.
+      description: A build with the common attributes of a Build Scan.
       required:
         - id
         - availableAt
@@ -788,12 +1302,10 @@ components:
         availableAt:
           type: integer
           format: int64
-          description: >-
-            The time in milliseconds from the Epoch as of when the Build Scan
-            has been received.
+          description: A unix-epoch-time in milliseconds referring to the instant that Gradle Enterprise completed receiving and processing the build.
         buildToolType:
           type: string
-          description: The build tool type used to caputre the Build Scan.
+          description: The build tool type used to capture the Build Scan.
         buildToolVersion:
           type: string
           description: The build tool version used.
@@ -804,16 +1316,14 @@ components:
       type: array
       items:
         $ref: '#/components/schemas/Build'
-      description: List of builds with basic attributes of a Build Scan.
+      description: List of builds with the common attributes of a Build Scan.
     BuildQuery:
       type: object
       properties:
         availabilityWaitTimeoutSecs:
           type: integer
           minimum: 0
-          description: >-
-            The time in seconds the server should wait for ingestion before
-            returning a wait timeout response.
+          description: The time in seconds the server should wait for ingestion before returning a wait timeout response.
     BuildAttributesValue:
       type: object
       description: A Build Scan value.
@@ -825,9 +1335,7 @@ components:
           description: The name of the Build Scan value.
         value:
           type: string
-          description: >-
-            The value of the Build Scan value. May be `null` if the Build Scan
-            value is not set.
+          description: The value of the Build Scan value. May be `null` if the Build Scan value is not set.
     BuildAttributesLink:
       type: object
       description: A Build Scan link.
@@ -847,35 +1355,19 @@ components:
       properties:
         backgroundPublicationEnabled:
           type: boolean
-          description: >-
-            Whether background Build Scan publication was enabled for the build.
-            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
-            Gradle plugin version is < `3.4`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
+          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
           x-nullable: true
         buildOutputCapturingEnabled:
           type: boolean
-          description: >-
-            Whether build logging output capturing was enabled for the build.
-            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
-            Gradle plugin version is < `3.7`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          description: Whether build logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
           x-nullable: true
         taskInputsFileCapturingEnabled:
           type: boolean
-          description: >-
-            Whether task input file snapshots capturing was enabled for the
-            build. May be `null` if Gradle version is < `5.0` or Gradle
-            Enterprise Gradle plugin version is < `2.1`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
+          description: Whether task input file snapshots capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
           x-nullable: true
         testOutputCapturingEnabled:
           type: boolean
-          description: >-
-            Whether test logging output capturing was enabled for the build. May
-            be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle
-            plugin version is < `3.7`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          description: Whether test logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
           x-nullable: true
     GradleBuildOptions:
       type: object
@@ -894,80 +1386,46 @@ components:
       properties:
         buildCacheEnabled:
           type: boolean
-          description: >-
-            Whether the build cache was enabled for the build. May be `null` if
-            Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version
-            is < `1.3`. See
-            https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
+          description: Whether the build cache was enabled for the build. May be `null` if Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version is < `1.3`. See https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
           x-nullable: true
         configurationCacheEnabled:
           type: boolean
-          description: >-
-            Whether the configuration cache was enabled for the build. May be
-            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
-            plugin version is < `3.4`. See
-            https://docs.gradle.org/current/userguide/configuration_cache.html.
+          description: Whether the configuration cache was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/configuration_cache.html.
           x-nullable: true
         configurationOnDemandEnabled:
           type: boolean
-          description: >-
-            Whether configuration on demand mode was enabled for the build. See
-            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
+          description: Whether configuration on demand mode was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
         continuousBuildEnabled:
           type: boolean
-          description: >-
-            Whether continuous build mode was running for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
+          description: Whether continuous build mode was running for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
         continueOnFailureEnabled:
           type: boolean
-          description: >-
-            Whether continue on failure mode was set for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
+          description: Whether continue on failure mode was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
         daemonEnabled:
           type: boolean
-          description: >-
-            Whether the build was run with the Gradle Daemon. See
-            https://docs.gradle.org/current/userguide/gradle_daemon.html.
+          description: Whether the build was run with the Gradle Daemon. See https://docs.gradle.org/current/userguide/gradle_daemon.html.
         dryRunEnabled:
           type: boolean
-          description: >-
-            Whether the dry run flag was set for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
+          description: Whether the dry run flag was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
         fileSystemWatchingEnabled:
           type: boolean
-          description: >-
-            Whether file system watching was enabled for the build. May be
-            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
-            plugin version is < `3.4`. See
-            https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:daemon_watch_fs.
+          description: Whether file system watching was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/file_system_watching.html.
           x-nullable: true
         maxNumberOfGradleWorkers:
           type: integer
-          description: >-
-            The maximum number of build workers used to run the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
+          description: The maximum number of build workers used to run the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
         offlineModeEnabled:
           type: boolean
-          description: >-
-            Whether the offline mode was set for the build. See
-            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
+          description: Whether the offline mode was set for the build. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
         parallelProjectExecutionEnabled:
           type: boolean
-          description: >-
-            Whether parallel project execution was enabled for the build. See
-            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
+          description: Whether parallel project execution was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
         refreshDependenciesEnabled:
           type: boolean
-          description: >-
-            Whether the build was set to refresh all dependencies in the
-            dependency cache. See
-            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
+          description: Whether the build was set to refresh all dependencies in the dependency cache. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
         rerunTasksEnabled:
           type: boolean
-          description: >-
-            Whether the build was forced to run all the tasks, ignoring any
-            up-to-date checks.
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
+          description: Whether the build was forced to run all the tasks, ignoring any up-to-date checks. https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
     BuildAttributesEnvironment:
       type: object
       description: The environment where the build has been executed.
@@ -981,9 +1439,7 @@ components:
       properties:
         username:
           type: string
-          description: >-
-            Operating system username of the build user. May be `null` if no
-            username was captured.
+          description: Operating system username of the build user. May be `null` if no username was captured.
           x-nullable: true
         operatingSystem:
           type: string
@@ -1003,32 +1459,24 @@ components:
           description: Maximum heap memory available to the build JVM in bytes.
         jvmCharset:
           type: string
-          description: >-
-            The default charset of the JVM that executed the build. May be
-            `null` if capturing was not possible.
+          description: The default charset of the JVM that executed the build. May be `null` if capturing was not possible.
           x-nullable: true
         jvmLocale:
           type: string
           description: The locale of the JVM that executed the build.
         publicHostname:
           type: string
-          description: >-
-            The hostname of the build machine, as seen on the network. May be
-            `null` if capturing was not possible.
+          description: The hostname of the build machine, as seen on the network. May be `null` if capturing was not possible.
           x-nullable: true
         localHostname:
           type: string
-          description: >-
-            The hostname of the build machine, as specified by itself. May be
-            `null` if capturing was not possible.
+          description: The hostname of the build machine, as specified by itself. May be `null` if capturing was not possible.
           x-nullable: true
         localIpAddresses:
           type: array
           items:
             type: string
-          description: >-
-            The local IP addresses of the build machine. May be `null` if
-            capturing was not possible.
+          description: The local IP addresses of the build machine. May be `null` if capturing was not possible.
           x-nullable: true
     GradleAttributes:
       type: object
@@ -1067,9 +1515,7 @@ components:
           description: The Gradle Enterprise Gradle plugin version used.
         rootProjectName:
           type: string
-          description: >-
-            The root project name. May be `null` in case of very early build
-            failure.
+          description: The root project name. May be `null` in case of very early build failure.
           x-nullable: true
         requestedTasks:
           type: array
@@ -1106,32 +1552,19 @@ components:
       properties:
         backgroundPublicationEnabled:
           type: boolean
-          description: >-
-            Whether background Build Scan publication was enabled for the build.
-            May be `null` if Gradle Enterprise Maven extension version is <
-            `1.6`. See
-            https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
+          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.6`. See https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
           x-nullable: true
         buildOutputCapturingEnabled:
           type: boolean
-          description: >-
-            Whether to capture build logging output for the build. May be `null`
-            if Gradle Enterprise Maven extension version is < `1.11`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          description: Whether to capture build logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
           x-nullable: true
         goalInputsFileCapturingEnabled:
           type: boolean
-          description: >-
-            Whether to capture goal input file snapshots for the build. May be
-            `null` if Gradle Enterprise Maven extension version is < `1.1`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
+          description: Whether to capture goal input file snapshots for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.1`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
           x-nullable: true
         testOutputCapturingEnabled:
           type: boolean
-          description: >-
-            Whether to capture test logging output for the build. May be `null`
-            if Gradle Enterprise Maven extension version is < `1.11`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          description: Whether to capture test logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
           x-nullable: true
     MavenBuildOptions:
       type: object
@@ -1146,101 +1579,58 @@ components:
       properties:
         batchModeEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to run in non-interactive (batch)
-            mode. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
+          description: Whether the build was configured to run in non-interactive (batch) mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
           x-nullable: true
         debugEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to produce execution debug output.
-            May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
+          description: Whether the build was configured to produce execution debug output. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
           x-nullable: true
         errorsEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to produce execution error
-            messages. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
+          description: Whether the build was configured to produce execution error messages. See https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
         failAtEndEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to only fail at the end. May be
-            `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
+          description: Whether the build was configured to only fail at the end. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
           x-nullable: true
         failFastEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to fail at the first error. May be
-            `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
+          description: Whether the build was configured to fail at the first error. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
           x-nullable: true
         failNeverEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to never fail, regardless of errors
-            produced. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
+          description: Whether the build was configured to never fail, regardless of errors produced. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
           x-nullable: true
         laxChecksumsEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to only warn if checksums don't
-            match. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
+          description: Whether the build was configured to only warn if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
           x-nullable: true
         maxNumberOfThreads:
           type: integer
-          description: >-
-            Maximum number of threads used when executing the build. See
-            https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
+          description: Maximum number of threads used when executing the build. See https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
         nonRecursiveEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to not recurse into sub-projects.
-            See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
+          description: Whether the build was configured to not recurse into sub-projects. See https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
         rerunGoals:
           type: boolean
-          description: >-
-            Whether the build was configured to rerun goals without checking the
-            build cache. May be `null` if Gradle Enterprise Maven extension
-            version is < `1.13`. See
-            https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
+          description: Whether the build was configured to rerun goals without checking the build cache. May be `null` if Gradle Enterprise Maven extension version is < `1.13`. See https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
           x-nullable: true
         noSnapshotsUpdatesEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to suppress snapshot updates. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
+          description: Whether the build was configured to suppress snapshot updates. See https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
         offlineModeEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to run offline. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
+          description: Whether the build was configured to run offline. See https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
         quietEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to run in quiet mode. May be `null`
-            if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
+          description: Whether the build was configured to run in quiet mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
           x-nullable: true
         strictChecksumsEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to fail if checksums don't match.
-            May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
+          description: Whether the build was configured to fail if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
           x-nullable: true
         updateSnapshotsEnabled:
           type: boolean
-          description: >-
-            Whether the build was configured to force a check for missing
-            releases and updated snapshots on remote repositories. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
+          description: Whether the build was configured to force a check for missing releases and updated snapshots on remote repositories. See https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
     MavenAttributes:
       type: object
       description: The attributes of a Maven Build Scan.
@@ -1278,9 +1668,7 @@ components:
           description: The Gradle Enterprise Maven extension version used.
         topLevelProjectName:
           type: string
-          description: >-
-            The top level project name. May be `null` in case of very early
-            build failure.
+          description: The top level project name. May be `null` in case of very early build failure.
           x-nullable: true
         requestedGoals:
           type: array
@@ -1315,6 +1703,7 @@ components:
       type: object
       required:
         - taskPath
+        - taskType
         - avoidanceOutcome
         - duration
       properties:
@@ -1354,19 +1743,12 @@ components:
         fingerprintingDuration:
           type: integer
           format: int64
-          description: >-
-            The task fingerprinting duration in milliseconds. This duration is
-            part of the complete task execution duration. May be `null` if the
-            task was not fingerprinted, or the information was not available.
+          description: The task fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the task was not fingerprinted, or the information was not available.
           x-nullable: true
         avoidanceSavings:
           type: integer
           format: int64
-          description: >-
-            The task avoidance savings in milliseconds, which can be negative.
-            Negative values indicate that it took more time to reuse outputs
-            than it did to create them originally. May be `null` if the
-            information was not available.
+          description: The task avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
           x-nullable: true
         nonCacheabilityCategory:
           type: string
@@ -1385,7 +1767,7 @@ components:
             - task_has_no_actions
             - task_output_caching_not_enabled
             - unknown
-          description: >
+          description: |
             The category of the non-cacheability reason:
               * `build_cache_not_enabled` - Caching has not been enabled for the build
               * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
@@ -1402,14 +1784,15 @@ components:
               * `task_output_caching_not_enabled` - Caching has not been enabled for the task
               * `unknown` - Reason for disabled caching was not known
 
-            May be `null` when the task was cacheable or if the information was
-            not available.
+            May be `null` when the task was cacheable or if the information was not available.
           x-nullable: true
         nonCacheabilityReason:
           type: string
-          description: >-
-            The human-readable reason for a non-cacheable task. May be `null`
-            when the task was cacheable or if the information was not available.
+          description: The human-readable reason for a non-cacheable task. May be `null` when the task was cacheable or if the information was not available.
+          x-nullable: true
+        skipReasonMessage:
+          type: string
+          description: The detailed reason why the task was skipped. May be `null` if the task was not skipped or Gradle versions <7.6 are used.
           x-nullable: true
     GradleBuildCachePerformanceTaskExecution:
       type: array
@@ -1418,11 +1801,7 @@ components:
         $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
     GradleBuildCachePerformanceTaskFingerprintingSummary:
       type: object
-      description: >-
-        A summary of task fingerprinting. Fingerprinted tasks are part of the
-        `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or
-        `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version
-        is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
+      description: A summary of task fingerprinting. Fingerprinted tasks are part of the `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
       x-nullable: true
       required:
         - count
@@ -1434,9 +1813,7 @@ components:
         serialDuration:
           type: integer
           format: int64
-          description: >-
-            Sum of all fingerprinting times of fingerprinted tasks in
-            milliseconds.
+          description: Sum of all fingerprinting times of fingerprinted tasks in milliseconds.
     GradleBuildCachePerformanceAvoidanceSavingsSummary:
       type: object
       description: A breakdown of avoidance savings.
@@ -1450,38 +1827,23 @@ components:
         total:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused in milliseconds.
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused in milliseconds.
         ratio:
           type: number
           format: double
-          description: >-
-            The ratio of the total avoidance savings against the potential
-            serial execution time (which is the actual serial execution time
-            plus the total avoidance savings). Quantifies the effect of
-            avoidance savings in this build. The bigger the ratio is, the more
-            time was saved when running the build.
+          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
         upToDate:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            build incrementalism in milliseconds.
+          description: The estimated reduction in serial execution time of the tasks due to build incrementalism in milliseconds.
         localBuildCache:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused from the local build cache in
-            milliseconds.
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the local build cache in milliseconds.
         remoteBuildCache:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused from the remote build cache in
-            milliseconds.
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the remote build cache in milliseconds.
     GradleBuildCachePerformanceBuildCacheLocalInfo:
       type: object
       description: Information about the local build cache used in the build.
@@ -1494,21 +1856,14 @@ components:
           description: Whether the local build cache was enabled.
         isPushEnabled:
           type: boolean
-          description: >-
-            Whether pushing to the local build cache was enabled.  May be `null`
-            if the local build cache is disabled.
+          description: Whether pushing to the local build cache was enabled.  May be `null` if the local build cache is disabled.
           x-nullable: true
         isDisabledDueToError:
           type: boolean
-          description: >-
-            Whether the local cache was disabled due to an error occuring in
-            loading or storing local build cache entries.
+          description: Whether the local cache was disabled due to an error occuring in loading or storing local build cache entries.
         directory:
           type: string
-          description: >-
-            Location of the local build cache. Can be relative or absolute
-            depending on its value. May be `null` if the local build cache is
-            disabled.
+          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
           x-nullable: true
     GradleBuildCachePerformanceBuildCacheRemoteInfo:
       type: object
@@ -1517,25 +1872,27 @@ components:
         - isEnabled
         - isDisabledDueToError
       properties:
+        type:
+          type: string
+          description: The type of the connector used to communicate with the remote build cache. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+        className:
+          type: string
+          description: The class name of the connector. May be `null` if the remote build cache is disabled.
+          x-nullable: true
         isEnabled:
           type: boolean
           description: Whether the remote build cache was enabled.
         isPushEnabled:
           type: boolean
-          description: >-
-            Whether pushing to the remote build cache was enabled. May be `null`
-            if the remote build cache is disabled.
+          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
           x-nullable: true
         isDisabledDueToError:
           type: boolean
-          description: >-
-            Wether the remote build cache was disabled during the build due to
-            an error occuring in loading or storing remote build cache entries.
+          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
         url:
           type: string
-          description: >-
-            URL of the remote build cache. May be `null` if the remote build
-            cache is disabled.
+          description: URL of the remote build cache. May be `null` if the remote build cache is disabled or if the given type is not supported or it doesn't have the concept of a URL.
           x-nullable: true
     GradleBuildCachePerformanceBuildCacheOverhead:
       type: object
@@ -1564,9 +1921,7 @@ components:
           description: Overhead of unpack operations in milliseconds.
     GradleBuildCachePerformanceBuildCaches:
       type: object
-      description: >-
-        Information about the local and remote build caches used in the build.
-        May be `null` if the build cache is globally disabled.
+      description: Information about the local and remote build caches used in the build. May be `null` if the build cache is globally disabled.
       x-nullable: true
       required:
         - local
@@ -1601,34 +1956,21 @@ components:
         effectiveTaskExecutionTime:
           type: integer
           format: int64
-          description: >-
-            Wall clock time spent executing tasks in milliseconds. It is the
-            time spent between the start of the first task in the execution
-            phase and the end of the last task of the execution phase, removing
-            any interval where no task is being executed.
+          description: Wall clock time spent executing tasks in milliseconds. It is the time spent between the start of the first task in the execution phase and the end of the last task of the execution phase, removing any interval where no task is being executed.
         serialTaskExecutionTime:
           type: integer
           format: int64
-          description: >-
-            Wall clock time of all task executions in milliseconds. It is the
-            sum of all individual task durations.
+          description: Wall clock time of all task executions in milliseconds. It is the sum of all individual task durations.
         serializationFactor:
           type: number
           format: double
-          description: >-
-            The ratio of `serialTaskExecutionTime` over the
-            `effectiveTaskExecutionTime`. Quantifies the effect of task
-            parallelization. A value equal to `1` means that no parallelization
-            occurred. A value greater than `1` means that tasks were executed
-            faster due to parallelization.
+          description: The ratio of `serialTaskExecutionTime` over the `effectiveTaskExecutionTime`. Quantifies the effect of task parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that tasks were executed faster due to parallelization.
         taskExecution:
           $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
         taskFingerprintingSummary:
-          $ref: >-
-            #/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary
+          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary'
         avoidanceSavingsSummary:
-          $ref: >-
-            #/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary
+          $ref: '#/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary'
         buildCaches:
           $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
     MavenBuildCachePerformanceGoalExecutionEntry:
@@ -1646,9 +1988,7 @@ components:
           description: The goal name.
         mojoType:
           type: string
-          description: >-
-            The fully qualified class name of the Mojo that provides the
-            implementation of this goal.
+          description: The fully qualified class name of the Mojo that provides the implementation of this goal.
         goalExecutionId:
           type: string
           description: The goal execution ID.
@@ -1679,19 +2019,12 @@ components:
         fingerprintingDuration:
           type: integer
           format: int64
-          description: >-
-            The goal fingerprinting duration in milliseconds. This duration is
-            part of the complete task execution duration. May be `null` if the
-            goal was not fingerprinted.
+          description: The goal fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the goal was not fingerprinted.
           x-nullable: true
         avoidanceSavings:
           type: integer
           format: int64
-          description: >-
-            The goal avoidance savings in milliseconds, which can be negative.
-            Negative values indicate that it took more time to reuse outputs
-            than it did to create them originally. May be `null` if the
-            information was not available.
+          description: The goal avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
           x-nullable: true
         nonCacheabilityCategory:
           type: string
@@ -1705,7 +2038,7 @@ components:
             - offline_build
             - unknown
             - unknown_entitlements
-          description: >
+          description: |
             The category of the non-cacheability reason:
               * `build_cache_disabled_by_user` - The build cache was disabled by the user
               * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
@@ -1717,15 +2050,11 @@ components:
               * `unknown` - Reason for disabled caching was not known
               * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
 
-            May be `null` when the goal execution was cacheable or if the
-            information was not available.
+            May be `null` when the goal execution was cacheable or if the information was not available.
           x-nullable: true
         nonCacheabilityReason:
           type: string
-          description: >-
-            The human-readable reason for a non-cacheable goal execution. May be
-            `null` when the goal execution was cacheable or if the information
-            was not available.
+          description: The human-readable reason for a non-cacheable goal execution. May be `null` when the goal execution was cacheable or if the information was not available.
           x-nullable: true
     MavenBuildCachePerformanceGoalExecution:
       type: array
@@ -1734,9 +2063,7 @@ components:
         $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
     MavenBuildCachePerformanceGoalFingerprintingSummary:
       type: object
-      description: >-
-        A summary of goal fingerprinting. Fingerprinted goals are part of the
-        `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
+      description: A summary of goal fingerprinting. Fingerprinted goals are part of the `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
       required:
         - count
         - serialDuration
@@ -1747,9 +2074,7 @@ components:
         serialDuration:
           type: integer
           format: int64
-          description: >-
-            Sum of all fingerprinting times of fingerprinted goals in
-            milliseconds.
+          description: Sum of all fingerprinting times of fingerprinted goals in milliseconds.
     MavenBuildCachePerformanceAvoidanceSavingsSummary:
       type: object
       description: A breakdown of avoidance savings.
@@ -1762,38 +2087,22 @@ components:
         total:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused in milliseconds.
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused in milliseconds.
         ratio:
           type: number
           format: double
-          description: >-
-            The ratio of the total avoidance savings against the potential
-            serial execution time (which is the actual serial execution time
-            plus the total avoidance savings). Quantifies the effect of
-            avoidance savings in this build. The bigger the ratio is, the more
-            time was saved when running the build.
+          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
         localBuildCache:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused from the local build cache in
-            milliseconds.
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the local build cache in milliseconds.
         remoteBuildCache:
           type: integer
           format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused from the remote build cache in
-            milliseconds.
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the remote build cache in milliseconds.
     MavenBuildCachePerformanceBuildCacheLocalInfo:
       type: object
-      description: >-
-        Information about the local build cache used in the build, if it was
-        configured in the build. May be `null` if the local build cache is not
-        configured.
+      description: Information about the local build cache used in the build, if it was configured in the build. May be `null` if the local build cache is not configured.
       x-nullable: true
       required:
         - isEnabled
@@ -1804,28 +2113,18 @@ components:
           description: Whether the local build cache was enabled.
         isPushEnabled:
           type: boolean
-          description: >-
-            Whether pushing to the local build cache was enabled. May be `null`
-            if the local build cache is disabled.
+          description: Whether pushing to the local build cache was enabled. May be `null` if the local build cache is disabled.
           x-nullable: true
         isDisabledDueToError:
           type: boolean
-          description: >-
-            Whether the local cache was disabled due to an error occuring in
-            loading or storing local build cache entries.
+          description: Whether the local cache was disabled due to an error occurring in loading or storing local build cache entries.
         directory:
           type: string
-          description: >-
-            Location of the local build cache. Can be relative or absolute
-            depending on its value. May be `null` if the local build cache is
-            disabled.
+          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
           x-nullable: true
     MavenBuildCachePerformanceBuildCacheRemoteInfo:
       type: object
-      description: >-
-        Information about the remote build cache used in the build, if it was
-        configured in the build. May be `null` if the remote build cache is not
-        configured.
+      description: Information about the remote build cache used in the build, if it was configured in the build. May be `null` if the remote build cache is not configured.
       x-nullable: true
       required:
         - isEnabled
@@ -1836,20 +2135,14 @@ components:
           description: Whether the remote build cache was enabled.
         isPushEnabled:
           type: boolean
-          description: >-
-            Whether pushing to the remote build cache was enabled. May be `null`
-            if the remote build cache is disabled.
+          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
           x-nullable: true
         isDisabledDueToError:
           type: boolean
-          description: >-
-            Whether the remote build cache was disabled during the build due to
-            an error occuring in loading or storing remote build cache entries.
+          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
         url:
           type: string
-          description: >-
-            URL of the remote build cache. May be `null` if the remote build
-            cache is disabled.
+          description: URL of the remote build cache. May be `null` if the remote build cache is disabled.
           x-nullable: true
     MavenBuildCachePerformanceBuildCacheOverhead:
       type: object
@@ -1878,10 +2171,7 @@ components:
           description: Overhead of unpack operations in milliseconds.
     MavenBuildCachePerformanceBuildCaches:
       type: object
-      description: >-
-        Information about the local and remote build caches used in the build,
-        if it was configured in the build. May be `null` if the build cache
-        configuration could not be captured (e.g. very early build failure).
+      description: Information about the local and remote build caches used in the build, if it was configured in the build. May be `null` if the build cache configuration could not be captured (e.g. very early build failure).
       x-nullable: true
       required:
         - overhead
@@ -1915,40 +2205,77 @@ components:
         effectiveProjectExecutionTime:
           type: integer
           format: int64
-          description: >-
-            Wall clock time spent executing projects in milliseconds. It is the
-            time spent between the start of the first project execution and the
-            end of the last project execution, removing any interval where no
-            project is being executed.
+          description: Wall clock time spent executing projects in milliseconds. It is the time spent between the start of the first project execution and the end of the last project execution, removing any interval where no project is being executed.
         serialProjectExecutionTime:
           type: integer
           format: int64
-          description: >-
-            Wall clock time of all project executions in milliseconds. It is the
-            sum of all individual project durations.
+          description: Wall clock time of all project executions in milliseconds. It is the sum of all individual project durations.
         serializationFactor:
           type: number
           format: double
-          description: >-
-            The ratio of `serialProjectExecutionTime` over the
-            `effectiveProjectExecutionTime`. Quantifies the effect of project
-            parallelization. A value equal to `1` means that no parallelization
-            occurred. A value greater than `1` means that projects were executed
-            faster due to parallelization.
+          description: The ratio of `serialProjectExecutionTime` over the `effectiveProjectExecutionTime`. Quantifies the effect of project parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that projects were executed faster due to parallelization.
         goalExecution:
           $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
         goalFingerprintingSummary:
-          $ref: >-
-            #/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary
+          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary'
         avoidanceSavingsSummary:
-          $ref: >-
-            #/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary
+          $ref: '#/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary'
         buildCaches:
           $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
+    GradleProject:
+      type: object
+      description: A Gradle project.
+      required:
+        - name
+        - path
+      properties:
+        name:
+          type: string
+          description: The name of the project.
+        path:
+          type: string
+          description: The path of the project.
+        parent:
+          type: integer
+          x-nullable: true
+          description: The index of the parent of this Gradle project in the GradleProjects array. May be `null` if this project has no parent (i.e. root project of a build).
+    GradleProjects:
+      type: array
+      items:
+        $ref: '#/components/schemas/GradleProject'
+      description: List of Gradle projects including structural relationships.
+    MavenModule:
+      type: object
+      description: A Maven module.
+      required:
+        - name
+        - groupId
+        - artifactId
+        - version
+      properties:
+        name:
+          type: string
+          description: The name of the module.
+        groupId:
+          type: string
+          description: The group ID of the module.
+        artifactId:
+          type: string
+          description: The artifact ID of the module.
+        version:
+          type: string
+          description: The version of the module.
+        parent:
+          type: integer
+          x-nullable: true
+          description: The index of the parent of this Maven module in the MavenModules array. May be `null` if this module has no parent (i.e. top level project).
+    MavenModules:
+      type: array
+      items:
+        $ref: '#/components/schemas/MavenModule'
+      description: List of Maven modules including structural relationships.
     ReplicationConfiguration:
-      description: >-
-        Cached data replication configuration description. May be `null` if
-        replication is not configured.
+      description: Cached data replication configuration description. May be `null` if replication is not configured.
       type: object
       x-nullable: true
       required:
@@ -1985,36 +2312,191 @@ components:
         secret:
           type: string
           description: The secret associated with the Build Cache Node.
+    TestDistributionAgentPoolId:
+      description: The unique identifier of the Agent Pool.
+      type: string
+      minLength: 8
+      maxLength: 8
+      pattern: ^[a-z2-7]{8}$
+    TestDistributionAgentPoolConfigurationWithId:
+      description: An Agent Pool configuration.
+      type: object
+      required:
+        - id
+        - name
+        - minimumSize
+        - maximumSize
+        - capabilities
+        - orderIndex
+      properties:
+        id:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+          example: functional-test-agents
+        minimumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        maximumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        orderIndex:
+          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
+          type: integer
+          format: int32
+          minimum: 0
+        capabilities:
+          type: array
+          items:
+            type: string
+            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
+          example:
+            - jdk=17
+            - os=linux
+            - functional-test
+    TestDistributionAgentPoolPage:
+      description: A list of Agent Pools.
+      type: object
+      required:
+        - content
+      properties:
+        content:
+          type: array
+          description: A list of Agent Pool IDs.
+          items:
+            $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+    TestDistributionAgentPoolConfiguration:
+      description: An Agent Pool configuration.
+      type: object
+      required:
+        - name
+        - minimumSize
+        - maximumSize
+        - capabilities
+      properties:
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+          example: functional-test-agents
+        minimumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        maximumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        orderIndex:
+          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
+          type: integer
+          format: int32
+          x-nullable: true
+          minimum: 0
+        capabilities:
+          type: array
+          items:
+            type: string
+            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
+          example:
+            - jdk=17
+            - os=linux
+            - functional-test
+    TestDistributionAgentPoolStatus:
+      description: The status of an Agent Pool.
+      type: object
+      required:
+        - id
+        - name
+        - minimumSize
+        - maximumSize
+        - connectedAgents
+        - idleAgents
+        - desiredAgents
+      properties:
+        id:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+        minimumSize:
+          type: integer
+          format: int32
+        maximumSize:
+          type: integer
+          format: int32
+        connectedAgents:
+          type: integer
+          format: int32
+        idleAgents:
+          type: integer
+          format: int32
+        desiredAgents:
+          type: integer
+          format: int32
+    TestDistributionApiKeyPrefix:
+      description: A Test Distribution Agent API key prefix.
+      type: object
+      required:
+        - keyPrefix
+        - generatedAt
+      properties:
+        keyPrefix:
+          type: string
+          minLength: 26
+          maxLength: 26
+          pattern: ^[a-z2-7]{26}$
+          description: The Agent API key.
+        generatedAt:
+          type: string
+          format: date-time
+        lastUsedAt:
+          type: string
+          format: date-time
+          x-nullable: true
+        revokedAt:
+          type: string
+          format: date-time
+          x-nullable: true
+    TestDistributionApiKeyPrefixPage:
+      description: A list of Test Distribution Agent API key prefixes.
+      type: object
+      required:
+        - content
+      properties:
+        content:
+          type: array
+          items:
+            $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+    TestDistributionApiKey:
+      description: A Test Distribution Agent API key.
+      type: object
+      required:
+        - key
+      properties:
+        key:
+          type: string
+          minLength: 52
+          maxLength: 52
+          pattern: ^[a-z2-7]{52}$
+          description: The Agent API key.
   examples:
-    BuildDeletedApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-deleted
-        title: Build deleted.
-        detail: |
-          Build 9r4d13f0r3v3r has been deleted and is no longer available.
-        status: 400
-    NonApplicableModelApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-model-not-applicable
-        title: Build model is not applicable.
-        detail: >
-          Build model BuildCachePerformance is not available for build
-          9r4d13f0r3v3r because the build agent version is not supported.
-        status: 400
     RequestValidationApiProblemExample:
       value:
         type: urn:gradle:enterprise:api:problems:validation
         title: Request validation failed.
-        detail: >
-          Numeric instance is lower than the required minimum (minimum: 1,
-          found: 0) (Additional info: Query parameter: maxWaitSecs).
+        detail: |
+          Numeric instance is lower than the required minimum (minimum: 1, found: 0) (Additional info: Query parameter: maxWaitSecs).
         status: 400
     NotFoundApiProblemExample:
       value:
         type: urn:gradle:enterprise:api:problems:not-found
-        title: >-
-          The requested resource is not found or the permissions to know about
-          it are missing.
+        title: The requested resource is not found or the permissions to know about it are missing.
         status: 404
     UnexpectedErrorApiProblemExample:
       value:
@@ -2027,33 +2509,45 @@ components:
       value:
         type: urn:gradle:enterprise:api:problems:build-processing-incomplete
         title: Build processing is incomplete.
-        detail: >
-          The data of build 9r4d13f0r3v3r is not yet available for viewing.
-          Please try again later.
+        detail: |
+          The data of build 9r4d13f0r3v3r is not yet available for viewing. Please try again later.
         status: 503
     NodeNotSignedInProblemExample:
       value:
         type: urn:gradle:enterprise:api:problems:node-not-signed-in
-        title: >-
-          Node with name not-signed-in-node1 must be signed-in before this
-          operation can be performed.
+        title: Node with name not-signed-in-node1 must be signed-in before this operation can be performed.
         status: 503
+    ForbiddenUserExample:
+      value:
+        type: urn:gradle:enterprise:forbidden
+        title: Insufficient permissions
+        detail: User must have Test Distribution administration permission to access this endpoint.
+        status: 403
+    CapabilityValidationProblemExample:
+      value:
+        type: urn:gradle:enterprise:validation
+        title: Invalid request parameters
+        detail: One or more capabilities have an invalid format.
+        status: 400
 tags:
   - name: Builds
-    description: >
-      Endpoints related to retrieving details of a Build Scan of the Gradle
-      Enterprise instance. 
-
-      To access these endpoints the user requires the `Access build data via the
-      API` permission.
+    description: |
+      Endpoints related to retrieving details of a Build Scan of the Gradle Enterprise instance. 
+      To access these endpoints the user requires the `Access build data via the API` permission.
   - name: BuildCache
     x-displayName: Build Cache
-    description: >
-      Endpoints related to configuring the Build Cache nodes of the Gradle
-      Enterprise instance. 
-
-      To access these endpoints the user requires the `Configure build caches`
-      permission.
+    description: |
+      Endpoints related to configuring the Build Cache nodes of the Gradle Enterprise instance. 
+      To access these endpoints the user requires the `Configure build caches` permission.
+  - name: Meta
+    x-displayName: Meta
+    description: |
+      Endpoints related to the Gradle Enterprise installation and its state.
   - name: GradleEnterprise
     x-traitTag: true
     description: All endpoints of the Gradle Enterprise API.
+  - name: TestDistribution
+    x-displayName: Test Distribution
+    description: |
+      Endpoints related to the management of Test Distribution resources.
+      To access these endpoints the user requires the `Admin` permission.

From b13f84c728d9a8eea0c64fe0702ae79aac28b9c2 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Wed, 10 May 2023 16:45:02 +0200
Subject: [PATCH 04/57] Use EAPI classes in BuildScanDataLoader

---
 .../build.gradle.kts                          |  4 ++--
 .../loader/BuildScanDataLoader.java           | 21 +++++++++++++++++--
 .../loader/OfflineBuildScanDataLoader.java    |  9 ++++++--
 .../loader/OnlineBuildScanDataLoader.java     |  9 ++++++--
 .../build.gradle.kts                          | 17 ++++++++-------
 5 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 712bba40..732609b0 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -19,7 +19,7 @@ dependencies {
     implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
 
-    implementation("com.google.guava:guava:31.1-jre")
+    implementation("com.google.guava:guava:31.1-jre") // todo use implementation("javax.annotation:javax.annotation-api:1.3.2")
 }
 
 java {
@@ -55,4 +55,4 @@ sourceSets {
             srcDir(tasks.openApiGenerate)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
index 074f0b2c..6f336355 100644
--- a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -1,9 +1,26 @@
 package com.gradle.enterprise.loader;
 
+import com.gradle.enterprise.api.model.GradleAttributes;
+import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
+import com.gradle.enterprise.api.model.MavenAttributes;
+import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+
 public interface BuildScanDataLoader {
 
-    String loadDataForGradle();
+    Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle();
+
+    Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven();
+
+    final class Pair<S, T> {
+
+        public final S first;
+        public final T second;
+
+        public Pair(S first, T second) {
+            this.first = first;
+            this.second = second;
+        }
 
-    String loadDataForMaven();
+    }
 
 }
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index 1b0cd014..982c2797 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -1,14 +1,19 @@
 package com.gradle.enterprise.loader;
 
+import com.gradle.enterprise.api.model.GradleAttributes;
+import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
+import com.gradle.enterprise.api.model.MavenAttributes;
+import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+
 public class OfflineBuildScanDataLoader implements BuildScanDataLoader {
 
     @Override
-    public String loadDataForGradle() {
+    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle() {
         return null;
     }
 
     @Override
-    public String loadDataForMaven() {
+    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven() {
         return null;
     }
 
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 2a47c584..bdf925b9 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -1,14 +1,19 @@
 package com.gradle.enterprise.loader;
 
+import com.gradle.enterprise.api.model.GradleAttributes;
+import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
+import com.gradle.enterprise.api.model.MavenAttributes;
+import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+
 public class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
     @Override
-    public String loadDataForGradle() {
+    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle() {
         return null;
     }
 
     @Override
-    public String loadDataForMaven() {
+    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven() {
         return null;
     }
 
diff --git a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
index 9c35a306..3ac2c8c6 100644
--- a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
+++ b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
@@ -15,6 +15,8 @@ repositories {
 }
 
 dependencies {
+    implementation(project(":build-scan-data-loader-api"))
+
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
     implementation("com.squareup.okhttp3:okhttp-tls")
@@ -25,6 +27,7 @@ dependencies {
     implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
 
+    implementation("javax.annotation:javax.annotation-api:1.3.2")
     implementation("com.google.guava:guava:31.1-jre")
     implementation("info.picocli:picocli:4.7.3")
     annotationProcessor("info.picocli:picocli-codegen:4.7.3")
@@ -51,13 +54,13 @@ openApiGenerate {
     invokerPackage.set("com.gradle.enterprise.api.client")
     // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
     configOptions.set(mapOf(
-        "library" to "okhttp-gson",
-        "dateLibrary" to "java8",
-        "hideGenerationTimestamp" to "true",
-        "openApiNullable" to "false",
-        "useBeanValidation" to "false",
-        "disallowAdditionalPropertiesIfNotPresent" to "false",
-        "sourceFolder" to ""  // makes IDEs like IntelliJ more reliably interpret the class packages.
+            "library" to "okhttp-gson",
+            "dateLibrary" to "java8",
+            "hideGenerationTimestamp" to "true",
+            "openApiNullable" to "false",
+            "useBeanValidation" to "false",
+            "disallowAdditionalPropertiesIfNotPresent" to "false",
+            "sourceFolder" to ""  // makes IDEs like IntelliJ more reliably interpret the class packages.
     ))
 }
 

From 3e0e701f23b412e1ffff323dd7c40ef8d9ce72a9 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 14:31:55 +0200
Subject: [PATCH 05/57] Use OpenAPI generator plugin 6.6.0

---
 components/build-scan-data-loader-api/build.gradle.kts         | 2 +-
 components/fetch-build-scan-data-cmdline-tool/build.gradle.kts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 732609b0..1b776136 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -1,6 +1,6 @@
 plugins {
     id("java-library")
-    id("org.openapi.generator") version "6.5.0"
+    id("org.openapi.generator") version "6.6.0"
 }
 
 repositories {
diff --git a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
index 3ac2c8c6..581276af 100644
--- a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
+++ b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
@@ -5,7 +5,7 @@ plugins {
     id("java")
     id("jvm-test-suite")
     id("com.github.johnrengelman.shadow") version "8.1.1"
-    id("org.openapi.generator") version "6.5.0"
+    id("org.openapi.generator") version "6.6.0"
 }
 
 description = "Application to fetch build scan data using the Gradle Enterprise Export API"

From 9323acc7b9be9e7f80e3951273a06d7956262f72 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 14:54:39 +0200
Subject: [PATCH 06/57] Fine-tune dependencies

---
 components/build-scan-data-loader-api/build.gradle.kts | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 1b776136..6a343afc 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -7,7 +7,6 @@ repositories {
     mavenCentral()
 }
 
-// todo review dependencies
 dependencies {
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
@@ -19,7 +18,8 @@ dependencies {
     implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
 
-    implementation("com.google.guava:guava:31.1-jre") // todo use implementation("javax.annotation:javax.annotation-api:1.3.2")
+    implementation("javax.annotation:javax.annotation-api:1.3.2")
+    implementation("com.google.code.findbugs:jsr305:3.0.2")
 }
 
 java {
@@ -37,6 +37,7 @@ openApiGenerate {
     modelPackage.set("com.gradle.enterprise.api.model")
     apiPackage.set("com.gradle.enterprise.api")
     invokerPackage.set("com.gradle.enterprise.api.client")
+
     // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
     configOptions.set(mapOf(
             "library" to "okhttp-gson",
@@ -45,7 +46,8 @@ openApiGenerate {
             "openApiNullable" to "false",
             "useBeanValidation" to "false",
             "disallowAdditionalPropertiesIfNotPresent" to "false",
-            "sourceFolder" to ""  // makes IDEs like IntelliJ more reliably interpret the class packages.
+            "containerDefaultToNull" to "true",
+            "sourceFolder" to ""
     ))
 }
 

From b3ee0d6c728147726ca30d3a4dae71c5b01eed85 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 15:30:09 +0200
Subject: [PATCH 07/57] Download API specification file from the internet

---
 components/build-scan-data-loader-api/build.gradle.kts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 6a343afc..9215bc5c 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -1,8 +1,14 @@
+@file:Suppress("HasPlatformType")
+
 plugins {
     id("java-library")
     id("org.openapi.generator") version "6.6.0"
 }
 
+val gradleEnterpriseVersion = "2022.4"
+val apiUrl = "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-$gradleEnterpriseVersion-api.yaml"
+val apiSpecificationFile = objects.property(File::class).value(resources.text.fromUri(apiUrl).asFile()).map { file -> file.absolutePath }
+
 repositories {
     mavenCentral()
 }
@@ -31,7 +37,7 @@ java {
 
 openApiGenerate {
     generatorName.set("java")
-    inputSpec.set("$projectDir/src/main/openapi/openapi.yaml")
+    inputSpec.set(apiSpecificationFile)
     outputDir.set("$buildDir/generated/gradle_enterprise_api")
     ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
     modelPackage.set("com.gradle.enterprise.api.model")

From 0b3d1cb80b0e5d6ddcd08a8ddaf54f9022d6e85b Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Thu, 11 May 2023 15:28:32 +0200
Subject: [PATCH 08/57] Update api module to only include the API model classes

The model classes have compile-time dependencies on a few client classes so
those need to be included as well.
---
 .../build-scan-data-loader-api/build.gradle.kts   | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 9215bc5c..4611d094 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -16,12 +16,8 @@ repositories {
 dependencies {
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
-    implementation("com.squareup.okhttp3:okhttp-tls")
-    implementation("com.squareup.okhttp3:logging-interceptor")
 
-    implementation("io.swagger:swagger-annotations:1.6.10")
     implementation("io.gsonfire:gson-fire:1.8.5")
-    implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
 
     implementation("javax.annotation:javax.annotation-api:1.3.2")
@@ -57,10 +53,19 @@ openApiGenerate {
     ))
 }
 
+val filterOpenApiGeneratedClasses by tasks.registering(Copy::class) {
+    from(tasks.openApiGenerate) {
+        include("com/gradle/enterprise/api/client/JSON.java")
+        include("com/gradle/enterprise/api/client/ApiException.java")
+        include("com/gradle/enterprise/api/model/**/*")
+    }
+    into(layout.buildDirectory.dir("generated-filtered"))
+}
+
 sourceSets {
     main {
         java {
-            srcDir(tasks.openApiGenerate)
+            srcDir(filterOpenApiGeneratedClasses)
         }
     }
 }

From f08959868abf41300c6ce2d0109269bb0c789e84 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Thu, 11 May 2023 15:30:13 +0200
Subject: [PATCH 09/57] Update the online loader to generate the OpenAPI client
 classes

...except for the model classes (which are in the API module).
---
 .../build.gradle.kts                          |    4 +
 .../.openapi-generator-ignore                 |    7 +
 .../build.gradle.kts                          |   62 +
 .../src/main/openapi/openapi.yaml             | 2553 +++++++++++++++++
 4 files changed, 2626 insertions(+)
 create mode 100644 components/build-scan-data-loader-online/.openapi-generator-ignore
 create mode 100644 components/build-scan-data-loader-online/src/main/openapi/openapi.yaml

diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index ff225483..d7783ef8 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -2,6 +2,10 @@ plugins {
     id("java-library")
 }
 
+repositories {
+    mavenCentral()
+}
+
 dependencies {
     api(project(":build-scan-data-loader-api"))
 }
diff --git a/components/build-scan-data-loader-online/.openapi-generator-ignore b/components/build-scan-data-loader-online/.openapi-generator-ignore
new file mode 100644
index 00000000..d70ed322
--- /dev/null
+++ b/components/build-scan-data-loader-online/.openapi-generator-ignore
@@ -0,0 +1,7 @@
+build/generated/gradle_enterprise_api/*
+build/generated/gradle_enterprise_api/.github/*
+build/generated/gradle_enterprise_api/api/*
+build/generated/gradle_enterprise_api/docs/*
+build/generated/gradle_enterprise_api/gradle/**/*
+build/generated/gradle_enterprise_api/src/main/AndroidManifest.xml
+build/generated/gradle_enterprise_api/src/test/**/*
diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
index ff225483..4bf9706f 100644
--- a/components/build-scan-data-loader-online/build.gradle.kts
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -1,11 +1,73 @@
 plugins {
     id("java-library")
+    id("org.openapi.generator") version "6.6.0"
+}
+
+val gradleEnterpriseVersion = "2022.4"
+val apiUrl = "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-$gradleEnterpriseVersion-api.yaml"
+val apiSpecificationFile = objects.property(File::class).value(resources.text.fromUri(apiUrl).asFile()).map { file -> file.absolutePath }
+
+repositories {
+    mavenCentral()
 }
 
 dependencies {
     api(project(":build-scan-data-loader-api"))
+
+    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
+    implementation("com.squareup.okhttp3:okhttp")
+    implementation("com.squareup.okhttp3:okhttp-tls")
+    implementation("com.squareup.okhttp3:logging-interceptor")
+
+    implementation("io.swagger:swagger-annotations:1.6.10")
+    implementation("io.gsonfire:gson-fire:1.8.5")
+    implementation("javax.ws.rs:jsr311-api:1.1.1")
+    implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
+
+    implementation("javax.annotation:javax.annotation-api:1.3.2")
+    implementation("com.google.code.findbugs:jsr305:3.0.2")
+}
+
+openApiGenerate {
+    generatorName.set("java")
+    inputSpec.set(apiSpecificationFile)
+    outputDir.set("$buildDir/generated/gradle_enterprise_api")
+    ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
+    modelPackage.set("com.gradle.enterprise.api.model")
+    apiPackage.set("com.gradle.enterprise.api")
+    invokerPackage.set("com.gradle.enterprise.api.client")
+
+    // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
+    configOptions.set(mapOf(
+        "library" to "okhttp-gson",
+        "dateLibrary" to "java8",
+        "hideGenerationTimestamp" to "true",
+        "openApiNullable" to "false",
+        "useBeanValidation" to "false",
+        "disallowAdditionalPropertiesIfNotPresent" to "false",
+        "containerDefaultToNull" to "true",
+        "sourceFolder" to ""
+    ))
+}
+
+val filterOpenApiGeneratedClasses by tasks.registering(Copy::class) {
+    from(tasks.openApiGenerate) {
+        include("com/gradle/enterprise/api/client/**/*")
+        exclude("com/gradle/enterprise/api/client/JSON.java")
+        exclude("com/gradle/enterprise/api/client/ApiException.java")
+    }
+    into(layout.buildDirectory.dir("generated-filtered"))
 }
 
+sourceSets {
+    main {
+        java {
+            srcDir(filterOpenApiGeneratedClasses)
+        }
+    }
+}
+
+
 java {
     toolchain {
         languageVersion.set(JavaLanguageVersion.of(8))
diff --git a/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml b/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml
new file mode 100644
index 00000000..8d7bfb30
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml
@@ -0,0 +1,2553 @@
+openapi: 3.0.3
+info:
+  title: Gradle Enterprise API
+  description: |
+    The Gradle Enterprise API allows programmatic interaction with various aspects of Gradle Enterprise, from configuration to inspecting build data.
+  version: "2022.4"
+  license:
+    name: Gradle Enterprise License
+    url: https://gradle.com/legal/gradle-enterprise-software-agreement
+  termsOfService: https://gradle.com/legal/terms-of-service
+  contact:
+    name: Gradle
+    url: https://gradle.com
+  x-logo:
+    url: https://assets.gradle.com/logo/gradle-enterprise-dark-green-primary.svg
+    altText: Gradle Enterprise
+servers:
+  - url: https://ge.mycompany.com
+    description: Your Gradle Enterprise instance.
+security:
+  - GradleEnterpriseAccessKey: []
+paths:
+  /api/builds:
+    description: |
+      Returns a list of builds with the common attributes of a Build Scan.
+      The returned list is capped by the `maxBuilds` and `maxWaitSecs` query parameters.
+      This endpoint supports pagination by using the `fromBuild` or `sinceBuild` query parameters, and the last returned build from a previous call to one of these endpoints.
+    parameters:
+      - in: query
+        name: BuildsQuery
+        explode: true
+        description: The query parameters used to retrieve the list of builds.
+        schema:
+          title: BuildsQuery
+          type: object
+          properties:
+            since:
+              type: integer
+              format: int64
+              minimum: 0
+              x-nullable: true
+              description: |
+                **This parameter is deprecated, use `fromInstant` instead.**
+                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant.
+                This parameter can only be used with `reverse=false`.
+                Therefore, a value of `0` will process all builds.
+                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
+                This parameter has no effect if any of `sinceBuild`, `fromInstant`, `fromBuild` are used.
+              deprecated: true
+            sinceBuild:
+              type: string
+              x-nullable: true
+              description: |
+                **This parameter is deprecated, use `fromBuild` instead.**
+                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it).
+                This parameter can only be used with `reverse=false`.
+                This parameter has precedence over any value set for the `since` parameter.
+                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
+                A Build Scan ID for a deleted build is valid.
+                This parameter has no effect if any of `fromInstant`, `fromBuild` are used.
+              deprecated: true
+            fromInstant:
+              type: integer
+              format: int64
+              minimum: 0
+              x-nullable: true
+              description: |
+                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant when used in conjunction with `reverse=false`, or before this instant when used in conjunction with `reverse=true`.
+                Therefore, a value of `0` will process all builds.
+                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
+                This parameter has no effect if `fromBuild` is used.
+            fromBuild:
+              type: string
+              x-nullable: true
+              description: |
+                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it) when used in conjunction with `reverse=false`, or before the given Build Scan ID (excluding it) when used in conjunction with `reverse=true`.
+                This parameter has precedence over any value set for the `since`, `sinceBuild`, `fromInstant` parameters.
+                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
+                A Build Scan ID for a deleted build is valid.
+            reverse:
+              type: boolean
+              x-nullable: true
+              description: |
+                A boolean indicating the time direction of the query.
+                A value of `true` indicates a backward query, and returned builds will be sorted from most to least recent.
+                A value of `false` indicates a forward query, and returned builds will be sorted from least to most recent.
+                This parameter has no effect if any of `since`, `sinceBuild` are used.
+                If not provided, the default value is `false`.
+            maxBuilds:
+              type: integer
+              minimum: 0
+              maximum: 1000
+              x-nullable: true
+              description: |
+                The maximum number of builds returned by the query.
+                The query returns when that number is reached or when `maxWaitSecs` is reached.
+                If not provided, the default value is `100`.
+            maxWaitSecs:
+              type: integer
+              minimum: 1
+              maximum: 20
+              x-nullable: true
+              description: |
+                The maximum number of seconds to wait for builds before returning.
+                If this time is reached before `maxBuilds` is reached, the query returns with the already processed builds.
+                Note that this time is respected with best effort.
+                A query will return soon after this time has passed but there is no guarantee that it exactly returns before this time has passed.
+                This parameter has no effect if `reverse=true` is specified, because new builds cannot become available in the past.
+                If not provided, the default value is `3`.
+    get:
+      operationId: GetBuilds
+      summary: Get a list of builds with the common attributes of a Build Scan.
+      description: The contained attributes are build tool agnostic.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: A list of builds with the common attributes of a Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Builds'
+              example:
+                - id: 9r4d13f0r3v3r
+                  availableAt: 1635400481000
+                  buildToolType: gradle
+                  buildToolVersion: '7.2'
+                  buildAgentVersion: 3.7.1
+                - id: ji7vz3ey5qdvk
+                  availableAt: 1635400482000
+                  buildToolType: maven
+                  buildToolVersion: 3.8.4
+                  buildAgentVersion: '1.13'
+                - id: cvpd4j7ug7j4q
+                  availableAt: 1635400483000
+                  buildToolType: bazel
+                  buildToolVersion: 6.0.0
+                  buildAgentVersion: '1.0'
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the common attributes of a Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetBuild
+      summary: Get the common attributes of a Build Scan.
+      description: The contained attributes are build tool agnostic.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The common attributes of a Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Build'
+              example:
+                id: 9r4d13f0r3v3r
+                availableAt: 1635400481000
+                buildToolType: gradle
+                buildToolVersion: '7.2'
+                buildAgentVersion: 3.7.1
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-attributes:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the attributes of a Gradle Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleAttributes
+      summary: Get the attributes of a Gradle Build Scan.
+      description: This model is Gradle specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The attributes of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleAttributes'
+              example:
+                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:
+                  - name: branch
+                    value: feature/one
+                  - name: commitId
+                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                links:
+                  - label: CI job
+                    url: https://ci.com/job1
+                  - label: GIT commit
+                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                gradleEnterpriseSettings:
+                  backgroundPublicationEnabled: true
+                  buildOutputCapturingEnabled: true
+                  taskInputsFileCapturingEnabled: true
+                  testOutputCapturingEnabled: true
+                buildOptions:
+                  buildCacheEnabled: true
+                  configurationCacheEnabled: true
+                  configurationOnDemandEnabled: true
+                  continuousBuildEnabled: true
+                  continueOnFailureEnabled: true
+                  daemonEnabled: true
+                  dryRunEnabled: true
+                  fileSystemWatchingEnabled: true
+                  maxNumberOfGradleWorkers: 4
+                  offlineModeEnabled: true
+                  parallelProjectExecutionEnabled: true
+                  refreshDependenciesEnabled: true
+                  rerunTasksEnabled: true
+                environment:
+                  username: gradle
+                  operatingSystem: macOS 12.2.1 (x86_64)
+                  numberOfCpuCores: 16
+                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
+                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
+                  jvmMaxMemoryHeapSize: 16777216
+                  jvmCharset: UTF-8
+                  jvmLocale: English (United States)
+                  publicHostname: agent.gradle.com
+                  localHostname: gradle
+                  localIpAddresses:
+                    - 192.168.1.126
+                    - 192.168.1.128
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-attributes:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the attributes of a Maven Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenAttributes
+      summary: Get the attributes of a Maven Build Scan.
+      description: This model is Maven specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The attributes of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenAttributes'
+              example:
+                id: 9r4d13f0r3v3r
+                buildStartTime: 1637316480
+                buildDuration: 11000
+                mavenVersion: 3.8.4
+                extensionVersion: 1.11.1
+                topLevelProjectName: example-project
+                requestedGoals:
+                  - clean
+                  - verify
+                hasFailed: false
+                tags:
+                  - CI
+                  - feature-branch
+                values:
+                  - name: branch
+                    value: feature/one
+                  - name: commitId
+                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                links:
+                  - label: CI job
+                    url: https://ci.com/job1
+                  - label: GIT commit
+                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
+                gradleEnterpriseSettings:
+                  backgroundPublicationEnabled: true
+                  buildOutputCapturingEnabled: true
+                  goalInputsFileCapturingEnabled: true
+                  testOutputCapturingEnabled: true
+                buildOptions:
+                  batchModeEnabled: true
+                  debugEnabled: true
+                  errorsEnabled: true
+                  failAtEndEnabled: true
+                  failFastEnabled: true
+                  failNeverEnabled: true
+                  laxChecksumsEnabled: true
+                  maxNumberOfThreads: 4
+                  nonRecursiveEnabled: true
+                  noSnapshotsUpdatesEnabled: true
+                  offlineModeEnabled: true
+                  quietEnabled: true
+                  rerunGoals: false
+                  strictChecksumsEnabled: true
+                  updateSnapshotsEnabled: true
+                environment:
+                  username: maven
+                  operatingSystem: macOS 12.2.1 (x86_64)
+                  numberOfCpuCores: 16
+                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
+                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
+                  jvmMaxMemoryHeapSize: 16777216
+                  jvmCharset: UTF-8
+                  jvmLocale: English (United States)
+                  publicHostname: agent.gradle.com
+                  localHostname: maven
+                  localIpAddresses:
+                    - 192.168.1.126
+                    - 192.168.1.128
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-build-cache-performance:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build cache performance of a Gradle Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleBuildCachePerformance
+      summary: Get the build cache performance of a Gradle Build Scan.
+      description: This model is Gradle specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The build cache performance of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleBuildCachePerformance'
+              example:
+                id: 9r4d13f0r3v3r
+                buildTime: 5000
+                effectiveTaskExecutionTime: 5000
+                serialTaskExecutionTime: 10000
+                serializationFactor: 2
+                taskExecution:
+                  - taskPath: ':task'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: avoided_from_local_cache
+                    duration: 5000
+                    fingerprintingDuration: 5
+                    avoidanceSavings: 6000
+                  - taskPath: ':task2'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: avoided_from_remote_cache
+                    duration: 3000
+                    fingerprintingDuration: 3
+                    avoidanceSavings: 4000
+                  - taskPath: ':task3'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: executed_not_cacheable
+                    duration: 2000
+                    fingerprintingDuration: 6
+                    nonCacheabilityCategory: cache-if_condition_not_matched
+                    nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
+                  - taskPath: ':task4'
+                    taskType: org.gradle.api.tasks.Task
+                    avoidanceOutcome: skipped
+                    duration: 0
+                    fingerprintingDuration: 0
+                    skipReasonMessage: some skip reason message
+                taskFingerprintingSummary:
+                  count: 1
+                  serialDuration: 8
+                avoidanceSavingsSummary:
+                  total: 10000
+                  ratio: 0.55556
+                  upToDate: 0
+                  localBuildCache: 6000
+                  remoteBuildCache: 4000
+                buildCaches:
+                  local:
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  remote:
+                    type: HTTP
+                    className: org.example.MyBuildCache
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  overhead:
+                    uploading: 100
+                    downloading: 200
+                    packing: 50
+                    unpacking: 25
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-build-cache-performance:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build cache performance of a Maven Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenBuildCachePerformance
+      summary: Get the build cache performance of a Maven Build Scan.
+      description: This model is Maven specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The build cache performance of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenBuildCachePerformance'
+              example:
+                id: 9r4d13f0r3v3r
+                buildTime: 5000
+                effectiveProjectExecutionTime: 5000
+                serialProjectExecutionTime: 10000
+                serializationFactor: 2
+                goalExecution:
+                  - goalName: clean:clean
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
+                    goalExecutionId: default-clean
+                    goalProjectName: myproject
+                    avoidanceOutcome: executed_not_cacheable
+                    duration: 2000
+                    nonCacheabilityCategory: build_cache_disabled_by_user
+                    nonCacheabilityReason: Neither the local or remote build cache were enabled in the configuration of the build.
+                  - goalName: compiler:compile
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
+                    goalExecutionId: default-compile
+                    goalProjectName: myproject
+                    avoidanceOutcome: avoided_from_local_cache
+                    duration: 5000
+                    fingerprintingDuration: 5
+                    avoidanceSavings: 6000
+                  - goalName: compiler:compile
+                    mojoType: org.apache.maven.plugin.jar.JarMojo
+                    goalExecutionId: default-compile
+                    goalProjectName: myproject2
+                    avoidanceOutcome: avoided_from_remote_cache
+                    duration: 3000
+                    fingerprintingDuration: 3
+                    avoidanceSavings: 4000
+                goalFingerprintingSummary:
+                  count: 1
+                  serialDuration: 8
+                avoidanceSavingsSummary:
+                  total: 10000
+                  ratio: 0.55556
+                  localBuildCache: 6000
+                  remoteBuildCache: 4000
+                buildCaches:
+                  local:
+                    isEnabled: true
+                    isDisabledDueToError: false
+                  remote:
+                    isEnabled: true
+                    isPushEnabled: true
+                    isDisabledDueToError: false
+                  overhead:
+                    uploading: 100
+                    downloading: 200
+                    packing: 50
+                    unpacking: 25
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/gradle-projects:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build structure of a Gradle Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetGradleProjects
+      summary: Get the projects of a Gradle Build Scan.
+      description: This model is Gradle specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The projects of a Gradle Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/GradleProjects'
+              example:
+                - name: root project
+                  path: ':'
+                - name: sub project
+                  path: ':sub'
+                  parent: 0
+                - name: included build root project
+                  path: ':included'
+                - name: included build sub project
+                  path: ':included:sub'
+                  parent: 2
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/builds/{id}/maven-modules:
+    parameters:
+      - in: path
+        name: id
+        schema:
+          type: string
+        required: true
+        description: The Build Scan ID.
+      - in: query
+        name: BuildQuery
+        explode: true
+        description: The query parameters used to retrieve the build structure of a Maven Build Scan.
+        schema:
+          $ref: '#/components/schemas/BuildQuery'
+    get:
+      operationId: GetMavenModules
+      summary: Get the modules of a Maven Build Scan.
+      description: This model is Maven specific and cannot be requested for another build tool.
+      tags:
+        - Builds
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The modules of a Maven Build Scan.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MavenModules'
+              example:
+                - name: top level project
+                  groupId: com
+                  artifactId: top-level
+                  version: '1.0'
+                - name: sub project a
+                  groupId: com
+                  artifactId: sub-a
+                  version: '1.1'
+                  parent: 0
+                - name: sub project b
+                  groupId: com
+                  artifactId: sub-b
+                  version: '2.0'
+                  parent: 0
+                - name: sub project a 2
+                  groupId: com
+                  artifactId: sub-a-a
+                  version: 2.1-SNAPSHOT
+                  parent: 1
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NotReadyError'
+  /api/build-cache/nodes/{name}:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
+    get:
+      operationId: GetBuildCacheNode
+      summary: View the configuration of a Build Cache Node.
+      description: View the enablement status and replication configuration of a Build Cache Node.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The configuration of a Build Cache Node.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/NodeConfiguration'
+              example:
+                enabled: false
+                replication:
+                  source: parent-node-1
+                  preemptive: true
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+    put:
+      operationId: CreateOrUpdateBuildCacheNode
+      summary: Create or update a Build Cache Node.
+      description: |
+        Create a new Build Cache Node in Gradle Enterprise or update the configuration of an existing one.
+        The Built-in Build Cache Node cannot be named as the target of this operation.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/NodeConfiguration'
+            example:
+              enabled: false
+              replication:
+                source: parent-node-1
+                preemptive: true
+      responses:
+        '200':
+          description: The name referenced an existing Build Cache Node and that Build Cache Node’s configuration was updated successfully.
+        '201':
+          description: A new Build Cache Node was created with the configuration specified in the request.
+        '400':
+          $ref: '#/components/responses/BadRequestError'
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+  /api/build-cache/nodes/{name}/secret:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: The name of the Build Cache Node.
+    post:
+      operationId: RegenerateSecretOfBuildCacheNode
+      summary: Regenerate the secret of a Build Cache Node.
+      description: |
+        Regenerates the secret associated with the named Build Cache Node. The old secret expires immediately, causing the Build Cache Node to
+        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot be named as the target of this operation.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The name referenced an existing Build Cache Node and that Build Cache Node's secret was regenerated.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/KeySecretPair'
+              example:
+                key: cvzxztkqkqxzc3vcruabpcr264
+                secret: e5ag76yp6abcc5jbxusboca313
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+  /api/build-cache/nodes/{name}/purge:
+    parameters:
+      - in: path
+        name: name
+        schema:
+          type: string
+        required: true
+        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
+    post:
+      operationId: InitiatePurgeOfBuildCacheNode
+      summary: Deletes all entries from a Build Cache Node.
+      description: |
+        Triggers the deletion of all entries stored at the named Build Cache Node.
+      tags:
+        - BuildCache
+        - GradleEnterprise
+      responses:
+        '202':
+          description: Purging the Build Cache Node was successfully initiated.
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+        '503':
+          $ref: '#/components/responses/NodeNotSignedInError'
+  /api/test-distribution/agent-pools:
+    get:
+      operationId: ListTestDistributionAgentPools
+      summary: Lists Agent Pools
+      description: Returns a list of all Agent Pools.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains a listing of all Agent Pools.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolPage'
+              example:
+                content:
+                  - id: m4yfaq4a
+                    name: abc-agents-pool
+                    minimumSize: 10
+                    maximumSize: 20
+                    capabilities:
+                      - os=linux
+                      - jdk=11
+                      - team-abc
+                    orderIndex: 1
+                  - id: dwc4whvi
+                    name: def-agents-pool
+                    minimumSize: 0
+                    maximumSize: 10
+                    capabilities:
+                      - os=windows
+                      - jdk=11
+                    orderIndex: 2
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    post:
+      operationId: CreateTestDistributionAgentPool
+      summary: Create an Agent Pool
+      description: |
+        Create a new Agent Pool in Gradle Enterprise.
+        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
+        When not specified, the Agent Pool will be added last.
+        When specified, the Agent Pool will be added at the specified index and all other Agent Pools will be moved down.
+        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
+            example:
+              name: abc-agents-pool
+              minimumSize: 10
+              maximumSize: 20
+              capabilities:
+                - os=linux
+                - jdk=11
+                - team-abc
+              orderIndex: 1
+      responses:
+        '200':
+          description: A new Agent Pool was created with the configuration specified in the request.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/agent-pools/{poolId}:
+    parameters:
+      - in: path
+        name: poolId
+        example: m4yfaq4a
+        schema:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        required: true
+        description: The ID of the pool to view.
+    get:
+      operationId: GetTestDistributionAgentPool
+      summary: View the properties of an Agent Pool
+      description: View the identifier, capabilities and size of an Agent Pool.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool whose configuration is described in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    put:
+      operationId: CreateOrUpdateTestDistributionAgentPool
+      summary: Create or update an Agent Pool
+      description: |
+        Create a new Agent Pool in Gradle Enterprise or update the configuration of an existing one.
+        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
+        When not specified, the Agent Pool will be either added last on creation, or will not change position on update.
+        When specified, the Agent Pool will be added at/moved to the specified index and all other Agent Pools will be moved down.
+        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
+            example:
+              name: abc-agents-pool
+              minimumSize: 10
+              maximumSize: 20
+              capabilities:
+                - os=linux
+                - jdk=11
+                - team-abc
+              orderIndex: 1
+      responses:
+        '200':
+          description: The Agent Pool was created or its configuration was updated successfully.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                capabilities:
+                  - os=linux
+                  - jdk=11
+                  - team-abc
+                orderIndex: 1
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    delete:
+      operationId: DeleteTestDistributionAgentPool
+      summary: Delete an Agent Pool
+      description: View the identifier, capabilities and size of an Agent Pool.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool and it was deleted.
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/agent-pools/{poolId}/status:
+    parameters:
+      - in: path
+        name: poolId
+        example: m4yfaq4a
+        schema:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        required: true
+        description: The ID of the pool to view.
+    get:
+      operationId: GetTestDistributionAgentPoolStatus
+      summary: View the status of an Agent Pool
+      description: |
+        View the status of an Agent Pool, such as its current size.
+        To access this endpoint the user requires the `Test Distribution` permission.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The poolId referenced an existing Agent Pool whose status is described in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionAgentPoolStatus'
+              example:
+                id: m4yfaq4a
+                name: abc-agents-pool
+                minimumSize: 10
+                maximumSize: 20
+                connectedAgents: 15
+                idleAgents: 5
+                desiredAgents: 10
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/api-keys:
+    get:
+      operationId: ListTestDistributionApiKeys
+      summary: Lists Test Distribution API keys
+      description: Returns a list of all Test Distribution API key prefixes.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains a listing of the requested type of (active or revoked) Test Distribution API keys.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefixPage'
+              example:
+                content:
+                  - keyPrefix: am3mbm5kamztbmrmygym5kamct
+                    generatedAt: '2021-01-01T12:59:59Z'
+                    lastUsedAt: '2021-05-03T10:11:02Z'
+                  - keyPrefix: yw3zbwjtnwthbxp3ym6ybxlnew
+                    generatedAt: '2021-04-20T13:21:43Z'
+                    revokedAt: '2022-10-12T11:22:33Z'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    post:
+      operationId: GenerateTestDistributionApiKey
+      summary: Generate a new Test Distribution API key
+      description: Generate a new Test Distribution API key to connect agents and query the agent pool API.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: A new API key was successfully generated and contained in the response.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKey'
+              example:
+                key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/test-distribution/api-keys/{keyPrefix}:
+    parameters:
+      - in: path
+        name: keyPrefix
+        example: riux3fkajs6ivtajxbrunelywk
+        schema:
+          type: string
+          minLength: 26
+          maxLength: 26
+          pattern: ^[a-z2-7]{26}$
+        required: true
+        description: The prefix of the Test Distribution API key.
+    get:
+      operationId: GetTestDistributionApiKey
+      summary: Get a Test Distribution API keyPrefix information.
+      description: Returns information about a Test Distribution API keyPrefix.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The response contains information about the requested Test Distribution API keyPrefix.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+              example:
+                keyPrefix: am3mbm5kamztbmrmygym5kamct
+                generatedAt: '2021-01-01T12:59:59Z'
+                lastUsedAt: '2021-05-03T10:11:02Z'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    put:
+      operationId: InsertTestDistributionApiKey
+      summary: Insert a specific Test Distribution API key
+      description: |
+        Inserts a specific Test Distribution API key to connect agents and query the agent pool API.
+        If a key with the same prefix but different key already exists, it will return 400.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/TestDistributionApiKey'
+            example:
+              key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
+      responses:
+        '200':
+          description: The API key was successfully inserted.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+              example:
+                keyPrefix: am3mbm5kamztbmrmygym5kamct
+                generatedAt: '2021-01-01T12:59:59Z'
+                lastUsedAt: '2021-05-03T10:11:02Z'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+    delete:
+      operationId: RevokeTestDistributionApiKey
+      summary: Revoke a Test Distribution API key
+      description: |
+        Revoke the Test Distribution API key for the given prefix which uniquely identifies a Test Distribution API key.
+        A revoked key can no longer be used to connect agents, but it will still be queryable and returned in the list.
+      tags:
+        - TestDistribution
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The API key was revoked successfully.
+        '403':
+          $ref: '#/components/responses/ForbiddenError'
+        '404':
+          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
+  /api/version:
+    get:
+      operationId: GetVersion
+      summary: Provides the version of Gradle Enterprise.
+      description: This endpoint can be accessed by any authenticated user.
+      tags:
+        - Meta
+        - GradleEnterprise
+      responses:
+        '200':
+          description: The version of Gradle Enterprise.
+          content:
+            application/json:
+              schema:
+                title: GradleEnterpriseVersion
+                type: object
+                required:
+                  - string
+                  - year
+                  - release
+                  - patch
+                properties:
+                  string:
+                    type: string
+                    description: The complete version string of format `YEAR.RELEASE.PATCH`, where the patch component is omitted when `0` (e.g. `2022.3`, `2022.3.1`).
+                  year:
+                    type: integer
+                    description: The gregorian calendar year of the release.
+                  release:
+                    type: integer
+                    description: The sequence number of the release for that year, starting with 1.
+                    minimum: 1
+                  patch:
+                    type: integer
+                    description: The patch level of the release, starting with 0.
+                    minimum: 0
+              examples:
+                '2022.3':
+                  value:
+                    string: '2022.3'
+                    year: 2022
+                    release: 3
+                    patch: 0
+                2022.3.1:
+                  value:
+                    string: 2022.3.1
+                    year: 2022
+                    release: 3
+                    patch: 1
+        '404':
+          $ref: '#/components/responses/NotFoundError'
+        '500':
+          $ref: '#/components/responses/UnexpectedError'
+components:
+  securitySchemes:
+    GradleEnterpriseAccessKey:
+      type: http
+      scheme: bearer
+      bearerFormat: Bearer <<Gradle Enterprise Access Key>>
+      description: |
+        All requests require a Gradle Enterprise access key as a bearer token. 
+        Given an access key of `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required header is `Authorization: Bearer l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
+
+        Please consult the [Gradle Enterprise API User Manual](https://docs.gradle.com/enterprise/api-manual#access_control) for guidance on how to provision access keys and check user permissions.
+  responses:
+    BadRequestError:
+      description: The request cannot be fulfilled due to a problem.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            RequestValidationApiProblemResponse:
+              $ref: '#/components/examples/RequestValidationApiProblemExample'
+    NotFoundError:
+      description: The referenced resource either does not exist or the permissions to know about it are missing.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            NotFoundResponse:
+              $ref: '#/components/examples/NotFoundApiProblemExample'
+    UnexpectedError:
+      description: The server encountered an unexpected error.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            UnexpectedErrorResponse:
+              $ref: '#/components/examples/UnexpectedErrorApiProblemExample'
+    NotReadyError:
+      description: The server is not ready to handle the request.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            IngestionNotCompletedResponse:
+              $ref: '#/components/examples/IngestionNotCompletedApiProblemExample'
+    NodeNotSignedInError:
+      description: The node was not signed in with Gradle Enterprise.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            NodeNotSignedInResponse:
+              $ref: '#/components/examples/NodeNotSignedInProblemExample'
+    ForbiddenError:
+      description: The authenticated user has insufficient permissions.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            ForbiddenUserResponse:
+              $ref: '#/components/examples/ForbiddenUserExample'
+    UnauthorizedOrNotFoundError:
+      description: No API key was specified in the request, the key has been revoked or the user bearing the key lacks permissions for this operation.
+    BadRequest:
+      description: The request body is malformed or contains invalid values for at least one of the properties.
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ApiProblem'
+          examples:
+            CapabilityValidationProblemResponse:
+              $ref: '#/components/examples/CapabilityValidationProblemExample'
+  schemas:
+    ApiProblem:
+      type: object
+      description: |
+        Response detailing why a request was rejected.
+        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807) standard (colloquially known as "Problem JSON") for the response format.
+      required:
+        - type
+        - title
+        - status
+      properties:
+        status:
+          type: integer
+          description: HTTP status code of the problem response.
+        type:
+          type: string
+          description: A URN (Uniform Resource Name) identifying the type of the problem.
+        title:
+          type: string
+          description: The underlying reason for the problem.
+        detail:
+          type: string
+          description: A longer and comprehensive description of the problem. May be `null` if not available.
+          x-nullable: true
+    Build:
+      type: object
+      description: A build with the common attributes of a Build Scan.
+      required:
+        - id
+        - availableAt
+        - buildToolType
+        - buildToolVersion
+        - buildAgentVersion
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        availableAt:
+          type: integer
+          format: int64
+          description: A unix-epoch-time in milliseconds referring to the instant that Gradle Enterprise completed receiving and processing the build.
+        buildToolType:
+          type: string
+          description: The build tool type used to capture the Build Scan.
+        buildToolVersion:
+          type: string
+          description: The build tool version used.
+        buildAgentVersion:
+          type: string
+          description: The build agent version used.
+    Builds:
+      type: array
+      items:
+        $ref: '#/components/schemas/Build'
+      description: List of builds with the common attributes of a Build Scan.
+    BuildQuery:
+      type: object
+      properties:
+        availabilityWaitTimeoutSecs:
+          type: integer
+          minimum: 0
+          description: The time in seconds the server should wait for ingestion before returning a wait timeout response.
+    BuildAttributesValue:
+      type: object
+      description: A Build Scan value.
+      required:
+        - name
+      properties:
+        name:
+          type: string
+          description: The name of the Build Scan value.
+        value:
+          type: string
+          description: The value of the Build Scan value. May be `null` if the Build Scan value is not set.
+    BuildAttributesLink:
+      type: object
+      description: A Build Scan link.
+      required:
+        - label
+        - url
+      properties:
+        label:
+          type: string
+          description: The label of the Build Scan link.
+        url:
+          type: string
+          description: The url  of the Build Scan link.
+    GradleGradleEnterpriseSettings:
+      type: object
+      description: Settings for Gradle Enterprise.
+      properties:
+        backgroundPublicationEnabled:
+          type: boolean
+          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
+          x-nullable: true
+        buildOutputCapturingEnabled:
+          type: boolean
+          description: Whether build logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          x-nullable: true
+        taskInputsFileCapturingEnabled:
+          type: boolean
+          description: Whether task input file snapshots capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
+          x-nullable: true
+        testOutputCapturingEnabled:
+          type: boolean
+          description: Whether test logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
+          x-nullable: true
+    GradleBuildOptions:
+      type: object
+      description: Gradle build options for this build.
+      required:
+        - configurationOnDemandEnabled
+        - continuousBuildEnabled
+        - continueOnFailureEnabled
+        - daemonEnabled
+        - dryRunEnabled
+        - maxNumberOfGradleWorkers
+        - offlineModeEnabled
+        - parallelProjectExecutionEnabled
+        - refreshDependenciesEnabled
+        - rerunTasksEnabled
+      properties:
+        buildCacheEnabled:
+          type: boolean
+          description: Whether the build cache was enabled for the build. May be `null` if Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version is < `1.3`. See https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
+          x-nullable: true
+        configurationCacheEnabled:
+          type: boolean
+          description: Whether the configuration cache was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/configuration_cache.html.
+          x-nullable: true
+        configurationOnDemandEnabled:
+          type: boolean
+          description: Whether configuration on demand mode was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
+        continuousBuildEnabled:
+          type: boolean
+          description: Whether continuous build mode was running for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
+        continueOnFailureEnabled:
+          type: boolean
+          description: Whether continue on failure mode was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
+        daemonEnabled:
+          type: boolean
+          description: Whether the build was run with the Gradle Daemon. See https://docs.gradle.org/current/userguide/gradle_daemon.html.
+        dryRunEnabled:
+          type: boolean
+          description: Whether the dry run flag was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
+        fileSystemWatchingEnabled:
+          type: boolean
+          description: Whether file system watching was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/file_system_watching.html.
+          x-nullable: true
+        maxNumberOfGradleWorkers:
+          type: integer
+          description: The maximum number of build workers used to run the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
+        offlineModeEnabled:
+          type: boolean
+          description: Whether the offline mode was set for the build. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
+        parallelProjectExecutionEnabled:
+          type: boolean
+          description: Whether parallel project execution was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
+        refreshDependenciesEnabled:
+          type: boolean
+          description: Whether the build was set to refresh all dependencies in the dependency cache. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
+        rerunTasksEnabled:
+          type: boolean
+          description: Whether the build was forced to run all the tasks, ignoring any up-to-date checks. https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
+    BuildAttributesEnvironment:
+      type: object
+      description: The environment where the build has been executed.
+      required:
+        - operatingSystem
+        - numberOfCpuCores
+        - jreVersion
+        - jvmVersion
+        - jvmMaxMemoryHeapSize
+        - jvmLocale
+      properties:
+        username:
+          type: string
+          description: Operating system username of the build user. May be `null` if no username was captured.
+          x-nullable: true
+        operatingSystem:
+          type: string
+          description: Operating system of the build machine.
+        numberOfCpuCores:
+          type: integer
+          description: Number of cores available to the build JVM.
+        jreVersion:
+          type: string
+          description: Version of the Java runtime that executed the build.
+        jvmVersion:
+          type: string
+          description: Version of the Java Virtual Machine that executed the build.
+        jvmMaxMemoryHeapSize:
+          type: integer
+          format: int64
+          description: Maximum heap memory available to the build JVM in bytes.
+        jvmCharset:
+          type: string
+          description: The default charset of the JVM that executed the build. May be `null` if capturing was not possible.
+          x-nullable: true
+        jvmLocale:
+          type: string
+          description: The locale of the JVM that executed the build.
+        publicHostname:
+          type: string
+          description: The hostname of the build machine, as seen on the network. May be `null` if capturing was not possible.
+          x-nullable: true
+        localHostname:
+          type: string
+          description: The hostname of the build machine, as specified by itself. May be `null` if capturing was not possible.
+          x-nullable: true
+        localIpAddresses:
+          type: array
+          items:
+            type: string
+          description: The local IP addresses of the build machine. May be `null` if capturing was not possible.
+          x-nullable: true
+    GradleAttributes:
+      type: object
+      description: The attributes of a Gradle Build Scan.
+      required:
+        - id
+        - buildStartTime
+        - buildDuration
+        - gradleVersion
+        - pluginVersion
+        - requestedTasks
+        - hasFailed
+        - tags
+        - values
+        - links
+        - gradleEnterpriseSettings
+        - buildOptions
+        - environment
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildStartTime:
+          type: integer
+          format: int64
+          description: The time when the build started, as milliseconds since Epoch.
+        buildDuration:
+          type: integer
+          format: int64
+          description: The duration of the build, as milliseconds since Epoch.
+        gradleVersion:
+          type: string
+          description: The Gradle version used.
+        pluginVersion:
+          type: string
+          description: The Gradle Enterprise Gradle plugin version used.
+        rootProjectName:
+          type: string
+          description: The root project name. May be `null` in case of very early build failure.
+          x-nullable: true
+        requestedTasks:
+          type: array
+          items:
+            type: string
+          description: The list of requested tasks.
+        hasFailed:
+          type: boolean
+          description: True when the build failed, false otherwise.
+        tags:
+          type: array
+          items:
+            type: string
+          description: The list of Build Scan tags.
+        values:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesValue'
+          description: The list of Build Scan values.
+        links:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesLink'
+          description: The list of Build Scan links.
+        gradleEnterpriseSettings:
+          $ref: '#/components/schemas/GradleGradleEnterpriseSettings'
+        buildOptions:
+          $ref: '#/components/schemas/GradleBuildOptions'
+        environment:
+          $ref: '#/components/schemas/BuildAttributesEnvironment'
+    MavenGradleEnterpriseSettings:
+      type: object
+      description: Settings for Gradle Enterprise.
+      properties:
+        backgroundPublicationEnabled:
+          type: boolean
+          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.6`. See https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
+          x-nullable: true
+        buildOutputCapturingEnabled:
+          type: boolean
+          description: Whether to capture build logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          x-nullable: true
+        goalInputsFileCapturingEnabled:
+          type: boolean
+          description: Whether to capture goal input file snapshots for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.1`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
+          x-nullable: true
+        testOutputCapturingEnabled:
+          type: boolean
+          description: Whether to capture test logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
+          x-nullable: true
+    MavenBuildOptions:
+      type: object
+      description: Maven build options for this build.
+      required:
+        - errorsEnabled
+        - maxNumberOfThreads
+        - nonRecursiveEnabled
+        - noSnapshotsUpdatesEnabled
+        - offlineModeEnabled
+        - updateSnapshotsEnabled
+      properties:
+        batchModeEnabled:
+          type: boolean
+          description: Whether the build was configured to run in non-interactive (batch) mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
+          x-nullable: true
+        debugEnabled:
+          type: boolean
+          description: Whether the build was configured to produce execution debug output. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
+          x-nullable: true
+        errorsEnabled:
+          type: boolean
+          description: Whether the build was configured to produce execution error messages. See https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
+        failAtEndEnabled:
+          type: boolean
+          description: Whether the build was configured to only fail at the end. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
+          x-nullable: true
+        failFastEnabled:
+          type: boolean
+          description: Whether the build was configured to fail at the first error. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
+          x-nullable: true
+        failNeverEnabled:
+          type: boolean
+          description: Whether the build was configured to never fail, regardless of errors produced. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
+          x-nullable: true
+        laxChecksumsEnabled:
+          type: boolean
+          description: Whether the build was configured to only warn if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
+          x-nullable: true
+        maxNumberOfThreads:
+          type: integer
+          description: Maximum number of threads used when executing the build. See https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
+        nonRecursiveEnabled:
+          type: boolean
+          description: Whether the build was configured to not recurse into sub-projects. See https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
+        rerunGoals:
+          type: boolean
+          description: Whether the build was configured to rerun goals without checking the build cache. May be `null` if Gradle Enterprise Maven extension version is < `1.13`. See https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
+          x-nullable: true
+        noSnapshotsUpdatesEnabled:
+          type: boolean
+          description: Whether the build was configured to suppress snapshot updates. See https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
+        offlineModeEnabled:
+          type: boolean
+          description: Whether the build was configured to run offline. See https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
+        quietEnabled:
+          type: boolean
+          description: Whether the build was configured to run in quiet mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
+          x-nullable: true
+        strictChecksumsEnabled:
+          type: boolean
+          description: Whether the build was configured to fail if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
+          x-nullable: true
+        updateSnapshotsEnabled:
+          type: boolean
+          description: Whether the build was configured to force a check for missing releases and updated snapshots on remote repositories. See https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
+    MavenAttributes:
+      type: object
+      description: The attributes of a Maven Build Scan.
+      required:
+        - id
+        - buildStartTime
+        - buildDuration
+        - mavenVersion
+        - extensionVersion
+        - requestedGoals
+        - hasFailed
+        - tags
+        - values
+        - links
+        - gradleEnterpriseSettings
+        - buildOptions
+        - environment
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildStartTime:
+          type: integer
+          format: int64
+          description: The time when the build started, as milliseconds since Epoch.
+        buildDuration:
+          type: integer
+          format: int64
+          description: The duration of the build, as milliseconds since Epoch.
+        mavenVersion:
+          type: string
+          description: The Maven version used.
+        extensionVersion:
+          type: string
+          description: The Gradle Enterprise Maven extension version used.
+        topLevelProjectName:
+          type: string
+          description: The top level project name. May be `null` in case of very early build failure.
+          x-nullable: true
+        requestedGoals:
+          type: array
+          items:
+            type: string
+          description: The list of requested goals.
+        hasFailed:
+          type: boolean
+          description: True when the build failed, false otherwise.
+        tags:
+          type: array
+          items:
+            type: string
+          description: The list of Build Scan tags.
+        values:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesValue'
+          description: The list of Build Scan values.
+        links:
+          type: array
+          items:
+            $ref: '#/components/schemas/BuildAttributesLink'
+          description: The list of Build Scan links.
+        gradleEnterpriseSettings:
+          $ref: '#/components/schemas/MavenGradleEnterpriseSettings'
+        buildOptions:
+          $ref: '#/components/schemas/MavenBuildOptions'
+        environment:
+          $ref: '#/components/schemas/BuildAttributesEnvironment'
+    GradleBuildCachePerformanceTaskExecutionEntry:
+      type: object
+      required:
+        - taskPath
+        - taskType
+        - avoidanceOutcome
+        - duration
+      properties:
+        taskPath:
+          type: string
+          description: The full task path.
+        taskType:
+          type: string
+          description: The fully qualified class name of the task.
+        avoidanceOutcome:
+          type: string
+          enum:
+            - avoided_up_to_date
+            - avoided_from_local_cache
+            - avoided_from_remote_cache
+            - executed_cacheable
+            - executed_not_cacheable
+            - executed_unknown_cacheability
+            - lifecycle
+            - no-source
+            - skipped
+          description: |
+            The avoidance outcome of this task with respect to performance:
+              * `avoided_up_to_date` - Task whose execution was avoided due to build incrementalism
+              * `avoided_from_local_cache` - Task whose execution was avoided due to reusing a local build cache entry
+              * `avoided_from_remote_cache` - Task whose execution was avoided due to reusing a remote build cache entry
+              * `executed_cacheable` - Task which was executed but was cacheable
+              * `executed_not_cacheable` - Task which was executed but was not cacheable
+              * `executed_unknown_cacheability` - Task which was executed and whose cacheability could not be determined
+              * `lifecycle` - Lifecycle task
+              * `no-source` - No-source task
+              * `skipped` - Skipped task
+        duration:
+          type: integer
+          format: int64
+          description: The task duration in milliseconds.
+        fingerprintingDuration:
+          type: integer
+          format: int64
+          description: The task fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the task was not fingerprinted, or the information was not available.
+          x-nullable: true
+        avoidanceSavings:
+          type: integer
+          format: int64
+          description: The task avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
+          x-nullable: true
+        nonCacheabilityCategory:
+          type: string
+          enum:
+            - build_cache_not_enabled
+            - cache-if_condition_not_matched
+            - disabled_to_ensure_correctness
+            - do-not-cache-if_condition_matched
+            - multiple_outputs_declared
+            - no_outputs_declared
+            - non_cacheable_inputs
+            - non_cacheable_task_action
+            - non_cacheable_task_implementation
+            - non_cacheable_tree_output
+            - overlapping_outputs
+            - task_has_no_actions
+            - task_output_caching_not_enabled
+            - unknown
+          description: |
+            The category of the non-cacheability reason:
+              * `build_cache_not_enabled` - Caching has not been enabled for the build
+              * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
+              * `disabled_to_ensure_correctness` - The task failed validation. Available since Gradle 7.0
+              * `do-not-cache-if_condition_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#doNotCacheIf`
+              * `multiple_outputs_declared` - The task declared multiple outputs
+              * `no_outputs_declared` - The task had no outputs declared
+              * `non_cacheable_inputs` - One of the task inputs was not cacheable, either because some type used as an input to the task was loaded via a custom classloader, or a Java lambda was used as an input. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_task_action` - One of the task actions was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_task_implementation` - The task implementation was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
+              * `non_cacheable_tree_output` - The task had a `org.gradle.api.file.FileTree` or a `org.gradle.api.internal.file.collections.DirectoryFileTree` as an output. Available since Gradle 5.0
+              * `overlapping_outputs` - The tasks outputs overlapped with another task. As Gradle cannot safely determine which task each output file belongs to, it disabled caching            
+              * `task_has_no_actions` - The task did not declare any actions
+              * `task_output_caching_not_enabled` - Caching has not been enabled for the task
+              * `unknown` - Reason for disabled caching was not known
+
+            May be `null` when the task was cacheable or if the information was not available.
+          x-nullable: true
+        nonCacheabilityReason:
+          type: string
+          description: The human-readable reason for a non-cacheable task. May be `null` when the task was cacheable or if the information was not available.
+          x-nullable: true
+        skipReasonMessage:
+          type: string
+          description: The detailed reason why the task was skipped. May be `null` if the task was not skipped or Gradle versions <7.6 are used.
+          x-nullable: true
+    GradleBuildCachePerformanceTaskExecution:
+      type: array
+      description: A list of executed tasks with performance related information.
+      items:
+        $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
+    GradleBuildCachePerformanceTaskFingerprintingSummary:
+      type: object
+      description: A summary of task fingerprinting. Fingerprinted tasks are part of the `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
+      x-nullable: true
+      required:
+        - count
+        - serialDuration
+      properties:
+        count:
+          type: integer
+          description: Count of fingerprinted tasks.
+        serialDuration:
+          type: integer
+          format: int64
+          description: Sum of all fingerprinting times of fingerprinted tasks in milliseconds.
+    GradleBuildCachePerformanceAvoidanceSavingsSummary:
+      type: object
+      description: A breakdown of avoidance savings.
+      required:
+        - total
+        - ratio
+        - upToDate
+        - localBuildCache
+        - remoteBuildCache
+      properties:
+        total:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused in milliseconds.
+        ratio:
+          type: number
+          format: double
+          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
+        upToDate:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the tasks due to build incrementalism in milliseconds.
+        localBuildCache:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the local build cache in milliseconds.
+        remoteBuildCache:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the remote build cache in milliseconds.
+    GradleBuildCachePerformanceBuildCacheLocalInfo:
+      type: object
+      description: Information about the local build cache used in the build.
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the local build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: Whether pushing to the local build cache was enabled.  May be `null` if the local build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: Whether the local cache was disabled due to an error occuring in loading or storing local build cache entries.
+        directory:
+          type: string
+          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
+          x-nullable: true
+    GradleBuildCachePerformanceBuildCacheRemoteInfo:
+      type: object
+      description: Information about the remote build cache used in the build.
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        type:
+          type: string
+          description: The type of the connector used to communicate with the remote build cache. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+        className:
+          type: string
+          description: The class name of the connector. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+        isEnabled:
+          type: boolean
+          description: Whether the remote build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
+        url:
+          type: string
+          description: URL of the remote build cache. May be `null` if the remote build cache is disabled or if the given type is not supported or it doesn't have the concept of a URL.
+          x-nullable: true
+    GradleBuildCachePerformanceBuildCacheOverhead:
+      type: object
+      description: Information about the build cache overhead in this build.
+      required:
+        - uploading
+        - downloading
+        - packing
+        - unpacking
+      properties:
+        uploading:
+          type: integer
+          format: int64
+          description: Overhead of upload operations in milliseconds.
+        downloading:
+          type: integer
+          format: int64
+          description: Overhead of download operations in milliseconds.
+        packing:
+          type: integer
+          format: int64
+          description: Overhead of pack operations in milliseconds.
+        unpacking:
+          type: integer
+          format: int64
+          description: Overhead of unpack operations in milliseconds.
+    GradleBuildCachePerformanceBuildCaches:
+      type: object
+      description: Information about the local and remote build caches used in the build. May be `null` if the build cache is globally disabled.
+      x-nullable: true
+      required:
+        - local
+        - remote
+        - overhead
+      properties:
+        local:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheLocalInfo'
+        remote:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheRemoteInfo'
+        overhead:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheOverhead'
+    GradleBuildCachePerformance:
+      type: object
+      description: The build cache performance of a Gradle Build Scan.
+      required:
+        - id
+        - buildTime
+        - effectiveTaskExecutionTime
+        - serialTaskExecutionTime
+        - serializationFactor
+        - taskExecution
+        - avoidanceSavingsSummary
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildTime:
+          type: integer
+          format: int64
+          description: Wall clock duration of the build in milliseconds.
+        effectiveTaskExecutionTime:
+          type: integer
+          format: int64
+          description: Wall clock time spent executing tasks in milliseconds. It is the time spent between the start of the first task in the execution phase and the end of the last task of the execution phase, removing any interval where no task is being executed.
+        serialTaskExecutionTime:
+          type: integer
+          format: int64
+          description: Wall clock time of all task executions in milliseconds. It is the sum of all individual task durations.
+        serializationFactor:
+          type: number
+          format: double
+          description: The ratio of `serialTaskExecutionTime` over the `effectiveTaskExecutionTime`. Quantifies the effect of task parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that tasks were executed faster due to parallelization.
+        taskExecution:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
+        taskFingerprintingSummary:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary'
+        avoidanceSavingsSummary:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary'
+        buildCaches:
+          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
+    MavenBuildCachePerformanceGoalExecutionEntry:
+      type: object
+      required:
+        - goalName
+        - mojoType
+        - goalExecutionId
+        - goalProjectName
+        - avoidanceOutcome
+        - duration
+      properties:
+        goalName:
+          type: string
+          description: The goal name.
+        mojoType:
+          type: string
+          description: The fully qualified class name of the Mojo that provides the implementation of this goal.
+        goalExecutionId:
+          type: string
+          description: The goal execution ID.
+        goalProjectName:
+          type: string
+          description: The goal project name.
+        avoidanceOutcome:
+          type: string
+          enum:
+            - avoided_from_local_cache
+            - avoided_from_remote_cache
+            - executed_cacheable
+            - executed_not_cacheable
+            - executed_unknown_cacheability
+            - skipped
+          description: |
+            The avoidance outcome of this task with respect to performance:
+              * `avoided_from_local_cache` - Goal whose execution was avoided due to reusing a local build cache entry
+              * `avoided_from_remote_cache` - Goal whose execution was avoided due to reusing a remote build cache entry
+              * `executed_cacheable` - Goal which was executed but was cacheable
+              * `executed_not_cacheable` - Goal which was executed but was not cacheable
+              * `executed_unknown_cacheability` - Goal which was executed and whose cacheability could not be determined
+              * `skipped` - Skipped goal
+        duration:
+          type: integer
+          format: int64
+          description: The goal duration in milliseconds.
+        fingerprintingDuration:
+          type: integer
+          format: int64
+          description: The goal fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the goal was not fingerprinted.
+          x-nullable: true
+        avoidanceSavings:
+          type: integer
+          format: int64
+          description: The goal avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
+          x-nullable: true
+        nonCacheabilityCategory:
+          type: string
+          enum:
+            - build_cache_disabled_by_user
+            - goal_execution_marked_non_cacheable
+            - goal_not_supported
+            - no_gradle_enterprise_server_configured
+            - non_clean_build
+            - not_entitled
+            - offline_build
+            - unknown
+            - unknown_entitlements
+          description: |
+            The category of the non-cacheability reason:
+              * `build_cache_disabled_by_user` - The build cache was disabled by the user
+              * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
+              * `goal_not_supported` - The goal did not support build caching
+              * `no_gradle_enterprise_server_configured` - No Gradle Enterprise server was configured
+              * `non_clean_build` - The `clean` lifecycle was not executed 
+              * `not_entitled` - The Gradle Enterprise license entitlements did not allow Maven build caching
+              * `offline_build` - The build was run in offline mode
+              * `unknown` - Reason for disabled caching was not known
+              * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
+
+            May be `null` when the goal execution was cacheable or if the information was not available.
+          x-nullable: true
+        nonCacheabilityReason:
+          type: string
+          description: The human-readable reason for a non-cacheable goal execution. May be `null` when the goal execution was cacheable or if the information was not available.
+          x-nullable: true
+    MavenBuildCachePerformanceGoalExecution:
+      type: array
+      description: A list of executed goals with performance related information.
+      items:
+        $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
+    MavenBuildCachePerformanceGoalFingerprintingSummary:
+      type: object
+      description: A summary of goal fingerprinting. Fingerprinted goals are part of the `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
+      required:
+        - count
+        - serialDuration
+      properties:
+        count:
+          type: integer
+          description: Count of fingerprinted goals.
+        serialDuration:
+          type: integer
+          format: int64
+          description: Sum of all fingerprinting times of fingerprinted goals in milliseconds.
+    MavenBuildCachePerformanceAvoidanceSavingsSummary:
+      type: object
+      description: A breakdown of avoidance savings.
+      required:
+        - total
+        - ratio
+        - localBuildCache
+        - remoteBuildCache
+      properties:
+        total:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused in milliseconds.
+        ratio:
+          type: number
+          format: double
+          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
+        localBuildCache:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the local build cache in milliseconds.
+        remoteBuildCache:
+          type: integer
+          format: int64
+          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the remote build cache in milliseconds.
+    MavenBuildCachePerformanceBuildCacheLocalInfo:
+      type: object
+      description: Information about the local build cache used in the build, if it was configured in the build. May be `null` if the local build cache is not configured.
+      x-nullable: true
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the local build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: Whether pushing to the local build cache was enabled. May be `null` if the local build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: Whether the local cache was disabled due to an error occurring in loading or storing local build cache entries.
+        directory:
+          type: string
+          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
+          x-nullable: true
+    MavenBuildCachePerformanceBuildCacheRemoteInfo:
+      type: object
+      description: Information about the remote build cache used in the build, if it was configured in the build. May be `null` if the remote build cache is not configured.
+      x-nullable: true
+      required:
+        - isEnabled
+        - isDisabledDueToError
+      properties:
+        isEnabled:
+          type: boolean
+          description: Whether the remote build cache was enabled.
+        isPushEnabled:
+          type: boolean
+          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+        isDisabledDueToError:
+          type: boolean
+          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
+        url:
+          type: string
+          description: URL of the remote build cache. May be `null` if the remote build cache is disabled.
+          x-nullable: true
+    MavenBuildCachePerformanceBuildCacheOverhead:
+      type: object
+      description: Information about the build cache overhead in this build.
+      required:
+        - uploading
+        - downloading
+        - packing
+        - unpacking
+      properties:
+        uploading:
+          type: integer
+          format: int64
+          description: Overhead of upload operations in milliseconds.
+        downloading:
+          type: integer
+          format: int64
+          description: Overhead of download operations in milliseconds.
+        packing:
+          type: integer
+          format: int64
+          description: Overhead of pack operations in milliseconds.
+        unpacking:
+          type: integer
+          format: int64
+          description: Overhead of unpack operations in milliseconds.
+    MavenBuildCachePerformanceBuildCaches:
+      type: object
+      description: Information about the local and remote build caches used in the build, if it was configured in the build. May be `null` if the build cache configuration could not be captured (e.g. very early build failure).
+      x-nullable: true
+      required:
+        - overhead
+      properties:
+        local:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheLocalInfo'
+        remote:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheRemoteInfo'
+        overhead:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheOverhead'
+    MavenBuildCachePerformance:
+      type: object
+      description: The build cache performance of a Maven Build Scan.
+      required:
+        - id
+        - buildTime
+        - effectiveProjectExecutionTime
+        - serialProjectExecutionTime
+        - serializationFactor
+        - goalExecution
+        - goalFingerprintingSummary
+        - avoidanceSavingsSummary
+      properties:
+        id:
+          type: string
+          description: The Build Scan ID.
+        buildTime:
+          type: integer
+          format: int64
+          description: Wall clock duration of the build in milliseconds.
+        effectiveProjectExecutionTime:
+          type: integer
+          format: int64
+          description: Wall clock time spent executing projects in milliseconds. It is the time spent between the start of the first project execution and the end of the last project execution, removing any interval where no project is being executed.
+        serialProjectExecutionTime:
+          type: integer
+          format: int64
+          description: Wall clock time of all project executions in milliseconds. It is the sum of all individual project durations.
+        serializationFactor:
+          type: number
+          format: double
+          description: The ratio of `serialProjectExecutionTime` over the `effectiveProjectExecutionTime`. Quantifies the effect of project parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that projects were executed faster due to parallelization.
+        goalExecution:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
+        goalFingerprintingSummary:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary'
+        avoidanceSavingsSummary:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary'
+        buildCaches:
+          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
+    GradleProject:
+      type: object
+      description: A Gradle project.
+      required:
+        - name
+        - path
+      properties:
+        name:
+          type: string
+          description: The name of the project.
+        path:
+          type: string
+          description: The path of the project.
+        parent:
+          type: integer
+          x-nullable: true
+          description: The index of the parent of this Gradle project in the GradleProjects array. May be `null` if this project has no parent (i.e. root project of a build).
+    GradleProjects:
+      type: array
+      items:
+        $ref: '#/components/schemas/GradleProject'
+      description: List of Gradle projects including structural relationships.
+    MavenModule:
+      type: object
+      description: A Maven module.
+      required:
+        - name
+        - groupId
+        - artifactId
+        - version
+      properties:
+        name:
+          type: string
+          description: The name of the module.
+        groupId:
+          type: string
+          description: The group ID of the module.
+        artifactId:
+          type: string
+          description: The artifact ID of the module.
+        version:
+          type: string
+          description: The version of the module.
+        parent:
+          type: integer
+          x-nullable: true
+          description: The index of the parent of this Maven module in the MavenModules array. May be `null` if this module has no parent (i.e. top level project).
+    MavenModules:
+      type: array
+      items:
+        $ref: '#/components/schemas/MavenModule'
+      description: List of Maven modules including structural relationships.
+    ReplicationConfiguration:
+      description: Cached data replication configuration description. May be `null` if replication is not configured.
+      type: object
+      x-nullable: true
+      required:
+        - source
+        - preemptive
+      properties:
+        source:
+          type: string
+          description: The name of the Build Cache Node which is the source of data.
+        preemptive:
+          type: boolean
+          description: Indicates if preemptive replication is enabled from the source.
+    NodeConfiguration:
+      description: A Build Cache Node configuration description.
+      type: object
+      required:
+        - enabled
+      properties:
+        enabled:
+          type: boolean
+          description: Indicates if the Build Cache Node is enabled.
+        replication:
+          $ref: '#/components/schemas/ReplicationConfiguration'
+    KeySecretPair:
+      description: A Build Cache Node key and secret pair.
+      type: object
+      required:
+        - key
+        - secret
+      properties:
+        key:
+          type: string
+          description: A unique identifier for the Build Cache Node in Gradle Enterprise.
+        secret:
+          type: string
+          description: The secret associated with the Build Cache Node.
+    TestDistributionAgentPoolId:
+      description: The unique identifier of the Agent Pool.
+      type: string
+      minLength: 8
+      maxLength: 8
+      pattern: ^[a-z2-7]{8}$
+    TestDistributionAgentPoolConfigurationWithId:
+      description: An Agent Pool configuration.
+      type: object
+      required:
+        - id
+        - name
+        - minimumSize
+        - maximumSize
+        - capabilities
+        - orderIndex
+      properties:
+        id:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+          example: functional-test-agents
+        minimumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        maximumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        orderIndex:
+          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
+          type: integer
+          format: int32
+          minimum: 0
+        capabilities:
+          type: array
+          items:
+            type: string
+            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
+          example:
+            - jdk=17
+            - os=linux
+            - functional-test
+    TestDistributionAgentPoolPage:
+      description: A list of Agent Pools.
+      type: object
+      required:
+        - content
+      properties:
+        content:
+          type: array
+          description: A list of Agent Pool IDs.
+          items:
+            $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
+    TestDistributionAgentPoolConfiguration:
+      description: An Agent Pool configuration.
+      type: object
+      required:
+        - name
+        - minimumSize
+        - maximumSize
+        - capabilities
+      properties:
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+          example: functional-test-agents
+        minimumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        maximumSize:
+          type: integer
+          format: int32
+          minimum: 0
+        orderIndex:
+          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
+          type: integer
+          format: int32
+          x-nullable: true
+          minimum: 0
+        capabilities:
+          type: array
+          items:
+            type: string
+            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
+          example:
+            - jdk=17
+            - os=linux
+            - functional-test
+    TestDistributionAgentPoolStatus:
+      description: The status of an Agent Pool.
+      type: object
+      required:
+        - id
+        - name
+        - minimumSize
+        - maximumSize
+        - connectedAgents
+        - idleAgents
+        - desiredAgents
+      properties:
+        id:
+          $ref: '#/components/schemas/TestDistributionAgentPoolId'
+        name:
+          type: string
+          description: The alias or display name of the Agent Pool.
+          minLength: 1
+        minimumSize:
+          type: integer
+          format: int32
+        maximumSize:
+          type: integer
+          format: int32
+        connectedAgents:
+          type: integer
+          format: int32
+        idleAgents:
+          type: integer
+          format: int32
+        desiredAgents:
+          type: integer
+          format: int32
+    TestDistributionApiKeyPrefix:
+      description: A Test Distribution Agent API key prefix.
+      type: object
+      required:
+        - keyPrefix
+        - generatedAt
+      properties:
+        keyPrefix:
+          type: string
+          minLength: 26
+          maxLength: 26
+          pattern: ^[a-z2-7]{26}$
+          description: The Agent API key.
+        generatedAt:
+          type: string
+          format: date-time
+        lastUsedAt:
+          type: string
+          format: date-time
+          x-nullable: true
+        revokedAt:
+          type: string
+          format: date-time
+          x-nullable: true
+    TestDistributionApiKeyPrefixPage:
+      description: A list of Test Distribution Agent API key prefixes.
+      type: object
+      required:
+        - content
+      properties:
+        content:
+          type: array
+          items:
+            $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
+    TestDistributionApiKey:
+      description: A Test Distribution Agent API key.
+      type: object
+      required:
+        - key
+      properties:
+        key:
+          type: string
+          minLength: 52
+          maxLength: 52
+          pattern: ^[a-z2-7]{52}$
+          description: The Agent API key.
+  examples:
+    RequestValidationApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:validation
+        title: Request validation failed.
+        detail: |
+          Numeric instance is lower than the required minimum (minimum: 1, found: 0) (Additional info: Query parameter: maxWaitSecs).
+        status: 400
+    NotFoundApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:not-found
+        title: The requested resource is not found or the permissions to know about it are missing.
+        status: 404
+    UnexpectedErrorApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:unexpected-error
+        title: Encountered an internal server error.
+        detail: |
+          The ingestion of build 9r4d13f0r3v3r failed.
+        status: 500
+    IngestionNotCompletedApiProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:build-processing-incomplete
+        title: Build processing is incomplete.
+        detail: |
+          The data of build 9r4d13f0r3v3r is not yet available for viewing. Please try again later.
+        status: 503
+    NodeNotSignedInProblemExample:
+      value:
+        type: urn:gradle:enterprise:api:problems:node-not-signed-in
+        title: Node with name not-signed-in-node1 must be signed-in before this operation can be performed.
+        status: 503
+    ForbiddenUserExample:
+      value:
+        type: urn:gradle:enterprise:forbidden
+        title: Insufficient permissions
+        detail: User must have Test Distribution administration permission to access this endpoint.
+        status: 403
+    CapabilityValidationProblemExample:
+      value:
+        type: urn:gradle:enterprise:validation
+        title: Invalid request parameters
+        detail: One or more capabilities have an invalid format.
+        status: 400
+tags:
+  - name: Builds
+    description: |
+      Endpoints related to retrieving details of a Build Scan of the Gradle Enterprise instance. 
+      To access these endpoints the user requires the `Access build data via the API` permission.
+  - name: BuildCache
+    x-displayName: Build Cache
+    description: |
+      Endpoints related to configuring the Build Cache nodes of the Gradle Enterprise instance. 
+      To access these endpoints the user requires the `Configure build caches` permission.
+  - name: Meta
+    x-displayName: Meta
+    description: |
+      Endpoints related to the Gradle Enterprise installation and its state.
+  - name: GradleEnterprise
+    x-traitTag: true
+    description: All endpoints of the Gradle Enterprise API.
+  - name: TestDistribution
+    x-displayName: Test Distribution
+    description: |
+      Endpoints related to the management of Test Distribution resources.
+      To access these endpoints the user requires the `Admin` permission.

From ca34dadbecc4d0255448b0dc990cd825ff1a926d Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Thu, 11 May 2023 15:56:42 +0200
Subject: [PATCH 10/57] Implement build-scan-data-loader-offline

The build scan dump reader is accessed via reflection.

Currently, the build-scan-dump-reader.jar is read from a file that is not checked-in to the repo. This means you will need the file in order for the build to succeed. This is temporary.
---
 .../loader/BuildScanDataLoader.java           |  6 +-
 .../build-scan-data-loader-offline/.gitignore |  1 +
 .../build.gradle.kts                          |  1 +
 .../loader/OfflineBuildScanDataLoader.java    | 21 ++++-
 .../loader/ReflectiveBuildScanDumpReader.java | 81 +++++++++++++++++++
 .../loader/OnlineBuildScanDataLoader.java     |  6 +-
 6 files changed, 108 insertions(+), 8 deletions(-)
 create mode 100644 components/build-scan-data-loader-offline/.gitignore
 create mode 100644 components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java

diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
index 6f336355..8d01af52 100644
--- a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -5,11 +5,13 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
+import java.net.URI;
+
 public interface BuildScanDataLoader {
 
-    Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle();
+    Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource);
 
-    Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven();
+    Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource);
 
     final class Pair<S, T> {
 
diff --git a/components/build-scan-data-loader-offline/.gitignore b/components/build-scan-data-loader-offline/.gitignore
new file mode 100644
index 00000000..7e44012e
--- /dev/null
+++ b/components/build-scan-data-loader-offline/.gitignore
@@ -0,0 +1 @@
+build-scan-dump-reader.jar
\ No newline at end of file
diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index d7783ef8..969a385a 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -8,6 +8,7 @@ repositories {
 
 dependencies {
     api(project(":build-scan-data-loader-api"))
+    "runtimeOnly"(files("build-scan-dump-reader.jar"))
 }
 
 java {
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index 982c2797..77074f77 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -5,16 +5,29 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
 public class OfflineBuildScanDataLoader implements BuildScanDataLoader {
+    private final ReflectiveBuildScanDumpReader reader;
+
+    private OfflineBuildScanDataLoader(ReflectiveBuildScanDumpReader reader) {
+        this.reader = reader;
+    }
+
+    public static OfflineBuildScanDataLoader newInstance(Path licenseFile) {
+        return new OfflineBuildScanDataLoader(ReflectiveBuildScanDumpReader.newInstance(licenseFile));
+    }
 
     @Override
-    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle() {
-        return null;
+    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
+        return reader.readGradleBuildScanDump(Paths.get(resource));
     }
 
     @Override
-    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven() {
-        return null;
+    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
+        return reader.readMavenBuildScanDump(Paths.get(resource));
     }
 
 }
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
new file mode 100644
index 00000000..3b1b15c2
--- /dev/null
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -0,0 +1,81 @@
+package com.gradle.enterprise.loader;
+
+import com.gradle.enterprise.api.model.GradleAttributes;
+import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
+import com.gradle.enterprise.api.model.MavenAttributes;
+import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+import com.gradle.enterprise.loader.BuildScanDataLoader.Pair;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+public class ReflectiveBuildScanDumpReader {
+
+    private final Object buildScanDumpReader;
+
+    private ReflectiveBuildScanDumpReader(Object buildScanDumpReader) {
+        this.buildScanDumpReader = buildScanDumpReader;
+    }
+
+    @SuppressWarnings("WeakerAccess")
+    public static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
+        try {
+            Class<?> buildScanDumpExtractorClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
+            Method newInstance = buildScanDumpExtractorClass.getMethod("newInstance", Path.class);
+            Object instance = newInstance.invoke(null, licenseFile);
+            return new ReflectiveBuildScanDumpReader(instance);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to find the Build Scan dump extractor.", e);
+        } catch (InvocationTargetException e) {
+            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            throw (RuntimeException) e.getCause();
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new RuntimeException("Unable to read Build Scan dumps: " + e.getMessage(), e);
+        }
+    }
+
+    @SuppressWarnings({"WeakerAccess", "unused"})
+    public Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
+        try {
+            Method extractGradleBuildScanDump = buildScanDumpReader.getClass().getMethod("readGradleBuildScanDump", Path.class);
+            Object gradleBuild = extractGradleBuildScanDump.invoke(buildScanDumpReader, scanDump);
+
+            GradleAttributes attributes = (GradleAttributes) gradleBuild.getClass().getField("attributes").get(gradleBuild);
+            GradleBuildCachePerformance  buildCachePerformance = (GradleBuildCachePerformance) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild);
+
+            return new Pair<>(attributes, buildCachePerformance);
+        } catch (InvocationTargetException e) {
+            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            throw (RuntimeException) e.getCause();
+        } catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException e) {
+            throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);
+        }
+    }
+
+    @SuppressWarnings({"WeakerAccess", "unused"})
+    public Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path scanDump) {
+        try {
+            Method extractMavenBuildScanDump = buildScanDumpReader.getClass().getMethod("readMavenBuildScanDump", Path.class);
+            Object mavenBuild = extractMavenBuildScanDump.invoke(buildScanDumpReader, scanDump);
+
+            MavenAttributes attributes = (MavenAttributes) mavenBuild.getClass().getField("attributes").get(mavenBuild);
+            MavenBuildCachePerformance buildCachePerformance = (MavenBuildCachePerformance) mavenBuild.getClass().getField("buildCachePerformance").get(mavenBuild);
+
+            return new Pair<>(attributes, buildCachePerformance);
+        } catch (InvocationTargetException e) {
+            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            throw (RuntimeException) e.getCause();
+        } catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException e) {
+            throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);
+        }
+    }
+
+    // TODO Remove
+    public static void main(String[] args) {
+        ReflectiveBuildScanDumpReader extractor = ReflectiveBuildScanDumpReader.newInstance(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise.aux.prod.license"));
+        Pair<GradleAttributes, GradleBuildCachePerformance> result = extractor.readGradleBuildScanDump(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise-gradle-build-validation/.data/02-validate-local-build-caching-same-location/20230511T111441-645cb201/second-build_ge-solutions/sample-projects/gradle/8.x/no-ge/build-scan-8.0.2-3.12.6-1683796487697-104c8ac5-cf01-4eb6-8b2d-f447d4803249.scan"));
+        System.out.println("Successfully fetched build scan dump data: " + result);
+    }
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index bdf925b9..57a77e82 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -5,15 +5,17 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
+import java.net.URI;
+
 public class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
     @Override
-    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle() {
+    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
         return null;
     }
 
     @Override
-    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven() {
+    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
         return null;
     }
 

From 36a68ea0d274afa347eaafad54c6ada630e0a3f4 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 16:11:32 +0200
Subject: [PATCH 11/57] Download API specification file via dependency
 resolution

---
 .../build.gradle.kts                          | 23 ++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 4611d094..9bb87908 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -11,9 +11,30 @@ val apiSpecificationFile = objects.property(File::class).value(resources.text.fr
 
 repositories {
     mavenCentral()
+
+    exclusiveContent {
+        forRepository {
+            ivy {
+                url = uri("https://docs.gradle.com/")
+                patternLayout {
+                    artifact("[organisation]/api-manual/ref/[artifact]-[revision]-api.[ext]")
+                }
+                metadataSources {
+                    artifact()
+                }
+            }
+        }
+        filter {
+            includeModule("enterprise", "gradle-enterprise")
+        }
+    }
 }
 
+val openApiSpec by configurations.creating
+
 dependencies {
+    openApiSpec("enterprise:gradle-enterprise:$gradleEnterpriseVersion@yaml")
+
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
 
@@ -33,7 +54,7 @@ java {
 
 openApiGenerate {
     generatorName.set("java")
-    inputSpec.set(apiSpecificationFile)
+    inputSpec.set(providers.provider { openApiSpec.singleFile.absolutePath })
     outputDir.set("$buildDir/generated/gradle_enterprise_api")
     ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
     modelPackage.set("com.gradle.enterprise.api.model")

From 2ebc094f3a8a8086610dd3073aedec4f21d32893 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 16:38:22 +0200
Subject: [PATCH 12/57] Minor

---
 components/build-scan-data-loader-api/build.gradle.kts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 9bb87908..025257ee 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -37,10 +37,8 @@ dependencies {
 
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
-
     implementation("io.gsonfire:gson-fire:1.8.5")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
-
     implementation("javax.annotation:javax.annotation-api:1.3.2")
     implementation("com.google.code.findbugs:jsr305:3.0.2")
 }

From 12db5a16b24762c7ae90106298fcc4aaf396e5d7 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 16:39:08 +0200
Subject: [PATCH 13/57] Remove dead code

---
 components/build-scan-data-loader-api/build.gradle.kts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 025257ee..50fe5fa2 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -6,8 +6,6 @@ plugins {
 }
 
 val gradleEnterpriseVersion = "2022.4"
-val apiUrl = "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-$gradleEnterpriseVersion-api.yaml"
-val apiSpecificationFile = objects.property(File::class).value(resources.text.fromUri(apiUrl).asFile()).map { file -> file.absolutePath }
 
 repositories {
     mavenCentral()

From 83473427b3590c5ad9d260cd8246baccfdd5f6ff Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 16:43:18 +0200
Subject: [PATCH 14/57] Remove openapi.yaml spec from repo since it is fetched
 with dependency resolution

---
 .../src/main/openapi/openapi.yaml             | 2553 -----------------
 1 file changed, 2553 deletions(-)
 delete mode 100644 components/build-scan-data-loader-api/src/main/openapi/openapi.yaml

diff --git a/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml b/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
deleted file mode 100644
index 8d7bfb30..00000000
--- a/components/build-scan-data-loader-api/src/main/openapi/openapi.yaml
+++ /dev/null
@@ -1,2553 +0,0 @@
-openapi: 3.0.3
-info:
-  title: Gradle Enterprise API
-  description: |
-    The Gradle Enterprise API allows programmatic interaction with various aspects of Gradle Enterprise, from configuration to inspecting build data.
-  version: "2022.4"
-  license:
-    name: Gradle Enterprise License
-    url: https://gradle.com/legal/gradle-enterprise-software-agreement
-  termsOfService: https://gradle.com/legal/terms-of-service
-  contact:
-    name: Gradle
-    url: https://gradle.com
-  x-logo:
-    url: https://assets.gradle.com/logo/gradle-enterprise-dark-green-primary.svg
-    altText: Gradle Enterprise
-servers:
-  - url: https://ge.mycompany.com
-    description: Your Gradle Enterprise instance.
-security:
-  - GradleEnterpriseAccessKey: []
-paths:
-  /api/builds:
-    description: |
-      Returns a list of builds with the common attributes of a Build Scan.
-      The returned list is capped by the `maxBuilds` and `maxWaitSecs` query parameters.
-      This endpoint supports pagination by using the `fromBuild` or `sinceBuild` query parameters, and the last returned build from a previous call to one of these endpoints.
-    parameters:
-      - in: query
-        name: BuildsQuery
-        explode: true
-        description: The query parameters used to retrieve the list of builds.
-        schema:
-          title: BuildsQuery
-          type: object
-          properties:
-            since:
-              type: integer
-              format: int64
-              minimum: 0
-              x-nullable: true
-              description: |
-                **This parameter is deprecated, use `fromInstant` instead.**
-                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant.
-                This parameter can only be used with `reverse=false`.
-                Therefore, a value of `0` will process all builds.
-                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
-                This parameter has no effect if any of `sinceBuild`, `fromInstant`, `fromBuild` are used.
-              deprecated: true
-            sinceBuild:
-              type: string
-              x-nullable: true
-              description: |
-                **This parameter is deprecated, use `fromBuild` instead.**
-                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it).
-                This parameter can only be used with `reverse=false`.
-                This parameter has precedence over any value set for the `since` parameter.
-                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
-                A Build Scan ID for a deleted build is valid.
-                This parameter has no effect if any of `fromInstant`, `fromBuild` are used.
-              deprecated: true
-            fromInstant:
-              type: integer
-              format: int64
-              minimum: 0
-              x-nullable: true
-              description: |
-                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant when used in conjunction with `reverse=false`, or before this instant when used in conjunction with `reverse=true`.
-                Therefore, a value of `0` will process all builds.
-                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
-                This parameter has no effect if `fromBuild` is used.
-            fromBuild:
-              type: string
-              x-nullable: true
-              description: |
-                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it) when used in conjunction with `reverse=false`, or before the given Build Scan ID (excluding it) when used in conjunction with `reverse=true`.
-                This parameter has precedence over any value set for the `since`, `sinceBuild`, `fromInstant` parameters.
-                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
-                A Build Scan ID for a deleted build is valid.
-            reverse:
-              type: boolean
-              x-nullable: true
-              description: |
-                A boolean indicating the time direction of the query.
-                A value of `true` indicates a backward query, and returned builds will be sorted from most to least recent.
-                A value of `false` indicates a forward query, and returned builds will be sorted from least to most recent.
-                This parameter has no effect if any of `since`, `sinceBuild` are used.
-                If not provided, the default value is `false`.
-            maxBuilds:
-              type: integer
-              minimum: 0
-              maximum: 1000
-              x-nullable: true
-              description: |
-                The maximum number of builds returned by the query.
-                The query returns when that number is reached or when `maxWaitSecs` is reached.
-                If not provided, the default value is `100`.
-            maxWaitSecs:
-              type: integer
-              minimum: 1
-              maximum: 20
-              x-nullable: true
-              description: |
-                The maximum number of seconds to wait for builds before returning.
-                If this time is reached before `maxBuilds` is reached, the query returns with the already processed builds.
-                Note that this time is respected with best effort.
-                A query will return soon after this time has passed but there is no guarantee that it exactly returns before this time has passed.
-                This parameter has no effect if `reverse=true` is specified, because new builds cannot become available in the past.
-                If not provided, the default value is `3`.
-    get:
-      operationId: GetBuilds
-      summary: Get a list of builds with the common attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: A list of builds with the common attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Builds'
-              example:
-                - id: 9r4d13f0r3v3r
-                  availableAt: 1635400481000
-                  buildToolType: gradle
-                  buildToolVersion: '7.2'
-                  buildAgentVersion: 3.7.1
-                - id: ji7vz3ey5qdvk
-                  availableAt: 1635400482000
-                  buildToolType: maven
-                  buildToolVersion: 3.8.4
-                  buildAgentVersion: '1.13'
-                - id: cvpd4j7ug7j4q
-                  availableAt: 1635400483000
-                  buildToolType: bazel
-                  buildToolVersion: 6.0.0
-                  buildAgentVersion: '1.0'
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the common attributes of a Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetBuild
-      summary: Get the common attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The common attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Build'
-              example:
-                id: 9r4d13f0r3v3r
-                availableAt: 1635400481000
-                buildToolType: gradle
-                buildToolVersion: '7.2'
-                buildAgentVersion: 3.7.1
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the attributes of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleAttributes
-      summary: Get the attributes of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleAttributes'
-              example:
-                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:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  taskInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  buildCacheEnabled: true
-                  configurationCacheEnabled: true
-                  configurationOnDemandEnabled: true
-                  continuousBuildEnabled: true
-                  continueOnFailureEnabled: true
-                  daemonEnabled: true
-                  dryRunEnabled: true
-                  fileSystemWatchingEnabled: true
-                  maxNumberOfGradleWorkers: 4
-                  offlineModeEnabled: true
-                  parallelProjectExecutionEnabled: true
-                  refreshDependenciesEnabled: true
-                  rerunTasksEnabled: true
-                environment:
-                  username: gradle
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: gradle
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the attributes of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenAttributes
-      summary: Get the attributes of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenAttributes'
-              example:
-                id: 9r4d13f0r3v3r
-                buildStartTime: 1637316480
-                buildDuration: 11000
-                mavenVersion: 3.8.4
-                extensionVersion: 1.11.1
-                topLevelProjectName: example-project
-                requestedGoals:
-                  - clean
-                  - verify
-                hasFailed: false
-                tags:
-                  - CI
-                  - feature-branch
-                values:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  goalInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  batchModeEnabled: true
-                  debugEnabled: true
-                  errorsEnabled: true
-                  failAtEndEnabled: true
-                  failFastEnabled: true
-                  failNeverEnabled: true
-                  laxChecksumsEnabled: true
-                  maxNumberOfThreads: 4
-                  nonRecursiveEnabled: true
-                  noSnapshotsUpdatesEnabled: true
-                  offlineModeEnabled: true
-                  quietEnabled: true
-                  rerunGoals: false
-                  strictChecksumsEnabled: true
-                  updateSnapshotsEnabled: true
-                environment:
-                  username: maven
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: maven
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build cache performance of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleBuildCachePerformance
-      summary: Get the build cache performance of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveTaskExecutionTime: 5000
-                serialTaskExecutionTime: 10000
-                serializationFactor: 2
-                taskExecution:
-                  - taskPath: ':task'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - taskPath: ':task2'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                  - taskPath: ':task3'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    fingerprintingDuration: 6
-                    nonCacheabilityCategory: cache-if_condition_not_matched
-                    nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
-                  - taskPath: ':task4'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: skipped
-                    duration: 0
-                    fingerprintingDuration: 0
-                    skipReasonMessage: some skip reason message
-                taskFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  upToDate: 0
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    type: HTTP
-                    className: org.example.MyBuildCache
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build cache performance of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenBuildCachePerformance
-      summary: Get the build cache performance of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveProjectExecutionTime: 5000
-                serialProjectExecutionTime: 10000
-                serializationFactor: 2
-                goalExecution:
-                  - goalName: clean:clean
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-clean
-                    goalProjectName: myproject
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    nonCacheabilityCategory: build_cache_disabled_by_user
-                    nonCacheabilityReason: Neither the local or remote build cache were enabled in the configuration of the build.
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject2
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                goalFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-projects:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build structure of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleProjects
-      summary: Get the projects of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The projects of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleProjects'
-              example:
-                - name: root project
-                  path: ':'
-                - name: sub project
-                  path: ':sub'
-                  parent: 0
-                - name: included build root project
-                  path: ':included'
-                - name: included build sub project
-                  path: ':included:sub'
-                  parent: 2
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-modules:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build structure of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenModules
-      summary: Get the modules of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The modules of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenModules'
-              example:
-                - name: top level project
-                  groupId: com
-                  artifactId: top-level
-                  version: '1.0'
-                - name: sub project a
-                  groupId: com
-                  artifactId: sub-a
-                  version: '1.1'
-                  parent: 0
-                - name: sub project b
-                  groupId: com
-                  artifactId: sub-b
-                  version: '2.0'
-                  parent: 0
-                - name: sub project a 2
-                  groupId: com
-                  artifactId: sub-a-a
-                  version: 2.1-SNAPSHOT
-                  parent: 1
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/build-cache/nodes/{name}:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
-    get:
-      operationId: GetBuildCacheNode
-      summary: View the configuration of a Build Cache Node.
-      description: View the enablement status and replication configuration of a Build Cache Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The configuration of a Build Cache Node.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/NodeConfiguration'
-              example:
-                enabled: false
-                replication:
-                  source: parent-node-1
-                  preemptive: true
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-    put:
-      operationId: CreateOrUpdateBuildCacheNode
-      summary: Create or update a Build Cache Node.
-      description: |
-        Create a new Build Cache Node in Gradle Enterprise or update the configuration of an existing one.
-        The Built-in Build Cache Node cannot be named as the target of this operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/NodeConfiguration'
-            example:
-              enabled: false
-              replication:
-                source: parent-node-1
-                preemptive: true
-      responses:
-        '200':
-          description: The name referenced an existing Build Cache Node and that Build Cache Node’s configuration was updated successfully.
-        '201':
-          description: A new Build Cache Node was created with the configuration specified in the request.
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-  /api/build-cache/nodes/{name}/secret:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node.
-    post:
-      operationId: RegenerateSecretOfBuildCacheNode
-      summary: Regenerate the secret of a Build Cache Node.
-      description: |
-        Regenerates the secret associated with the named Build Cache Node. The old secret expires immediately, causing the Build Cache Node to
-        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot be named as the target of this operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The name referenced an existing Build Cache Node and that Build Cache Node's secret was regenerated.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/KeySecretPair'
-              example:
-                key: cvzxztkqkqxzc3vcruabpcr264
-                secret: e5ag76yp6abcc5jbxusboca313
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-  /api/build-cache/nodes/{name}/purge:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
-    post:
-      operationId: InitiatePurgeOfBuildCacheNode
-      summary: Deletes all entries from a Build Cache Node.
-      description: |
-        Triggers the deletion of all entries stored at the named Build Cache Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '202':
-          description: Purging the Build Cache Node was successfully initiated.
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NodeNotSignedInError'
-  /api/test-distribution/agent-pools:
-    get:
-      operationId: ListTestDistributionAgentPools
-      summary: Lists Agent Pools
-      description: Returns a list of all Agent Pools.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains a listing of all Agent Pools.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolPage'
-              example:
-                content:
-                  - id: m4yfaq4a
-                    name: abc-agents-pool
-                    minimumSize: 10
-                    maximumSize: 20
-                    capabilities:
-                      - os=linux
-                      - jdk=11
-                      - team-abc
-                    orderIndex: 1
-                  - id: dwc4whvi
-                    name: def-agents-pool
-                    minimumSize: 0
-                    maximumSize: 10
-                    capabilities:
-                      - os=windows
-                      - jdk=11
-                    orderIndex: 2
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    post:
-      operationId: CreateTestDistributionAgentPool
-      summary: Create an Agent Pool
-      description: |
-        Create a new Agent Pool in Gradle Enterprise.
-        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
-        When not specified, the Agent Pool will be added last.
-        When specified, the Agent Pool will be added at the specified index and all other Agent Pools will be moved down.
-        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
-            example:
-              name: abc-agents-pool
-              minimumSize: 10
-              maximumSize: 20
-              capabilities:
-                - os=linux
-                - jdk=11
-                - team-abc
-              orderIndex: 1
-      responses:
-        '200':
-          description: A new Agent Pool was created with the configuration specified in the request.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/agent-pools/{poolId}:
-    parameters:
-      - in: path
-        name: poolId
-        example: m4yfaq4a
-        schema:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        required: true
-        description: The ID of the pool to view.
-    get:
-      operationId: GetTestDistributionAgentPool
-      summary: View the properties of an Agent Pool
-      description: View the identifier, capabilities and size of an Agent Pool.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool whose configuration is described in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    put:
-      operationId: CreateOrUpdateTestDistributionAgentPool
-      summary: Create or update an Agent Pool
-      description: |
-        Create a new Agent Pool in Gradle Enterprise or update the configuration of an existing one.
-        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
-        When not specified, the Agent Pool will be either added last on creation, or will not change position on update.
-        When specified, the Agent Pool will be added at/moved to the specified index and all other Agent Pools will be moved down.
-        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
-            example:
-              name: abc-agents-pool
-              minimumSize: 10
-              maximumSize: 20
-              capabilities:
-                - os=linux
-                - jdk=11
-                - team-abc
-              orderIndex: 1
-      responses:
-        '200':
-          description: The Agent Pool was created or its configuration was updated successfully.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    delete:
-      operationId: DeleteTestDistributionAgentPool
-      summary: Delete an Agent Pool
-      description: View the identifier, capabilities and size of an Agent Pool.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool and it was deleted.
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/agent-pools/{poolId}/status:
-    parameters:
-      - in: path
-        name: poolId
-        example: m4yfaq4a
-        schema:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        required: true
-        description: The ID of the pool to view.
-    get:
-      operationId: GetTestDistributionAgentPoolStatus
-      summary: View the status of an Agent Pool
-      description: |
-        View the status of an Agent Pool, such as its current size.
-        To access this endpoint the user requires the `Test Distribution` permission.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool whose status is described in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolStatus'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                connectedAgents: 15
-                idleAgents: 5
-                desiredAgents: 10
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/api-keys:
-    get:
-      operationId: ListTestDistributionApiKeys
-      summary: Lists Test Distribution API keys
-      description: Returns a list of all Test Distribution API key prefixes.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains a listing of the requested type of (active or revoked) Test Distribution API keys.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefixPage'
-              example:
-                content:
-                  - keyPrefix: am3mbm5kamztbmrmygym5kamct
-                    generatedAt: '2021-01-01T12:59:59Z'
-                    lastUsedAt: '2021-05-03T10:11:02Z'
-                  - keyPrefix: yw3zbwjtnwthbxp3ym6ybxlnew
-                    generatedAt: '2021-04-20T13:21:43Z'
-                    revokedAt: '2022-10-12T11:22:33Z'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    post:
-      operationId: GenerateTestDistributionApiKey
-      summary: Generate a new Test Distribution API key
-      description: Generate a new Test Distribution API key to connect agents and query the agent pool API.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: A new API key was successfully generated and contained in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKey'
-              example:
-                key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/api-keys/{keyPrefix}:
-    parameters:
-      - in: path
-        name: keyPrefix
-        example: riux3fkajs6ivtajxbrunelywk
-        schema:
-          type: string
-          minLength: 26
-          maxLength: 26
-          pattern: ^[a-z2-7]{26}$
-        required: true
-        description: The prefix of the Test Distribution API key.
-    get:
-      operationId: GetTestDistributionApiKey
-      summary: Get a Test Distribution API keyPrefix information.
-      description: Returns information about a Test Distribution API keyPrefix.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains information about the requested Test Distribution API keyPrefix.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-              example:
-                keyPrefix: am3mbm5kamztbmrmygym5kamct
-                generatedAt: '2021-01-01T12:59:59Z'
-                lastUsedAt: '2021-05-03T10:11:02Z'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    put:
-      operationId: InsertTestDistributionApiKey
-      summary: Insert a specific Test Distribution API key
-      description: |
-        Inserts a specific Test Distribution API key to connect agents and query the agent pool API.
-        If a key with the same prefix but different key already exists, it will return 400.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionApiKey'
-            example:
-              key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
-      responses:
-        '200':
-          description: The API key was successfully inserted.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-              example:
-                keyPrefix: am3mbm5kamztbmrmygym5kamct
-                generatedAt: '2021-01-01T12:59:59Z'
-                lastUsedAt: '2021-05-03T10:11:02Z'
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    delete:
-      operationId: RevokeTestDistributionApiKey
-      summary: Revoke a Test Distribution API key
-      description: |
-        Revoke the Test Distribution API key for the given prefix which uniquely identifies a Test Distribution API key.
-        A revoked key can no longer be used to connect agents, but it will still be queryable and returned in the list.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The API key was revoked successfully.
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/version:
-    get:
-      operationId: GetVersion
-      summary: Provides the version of Gradle Enterprise.
-      description: This endpoint can be accessed by any authenticated user.
-      tags:
-        - Meta
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The version of Gradle Enterprise.
-          content:
-            application/json:
-              schema:
-                title: GradleEnterpriseVersion
-                type: object
-                required:
-                  - string
-                  - year
-                  - release
-                  - patch
-                properties:
-                  string:
-                    type: string
-                    description: The complete version string of format `YEAR.RELEASE.PATCH`, where the patch component is omitted when `0` (e.g. `2022.3`, `2022.3.1`).
-                  year:
-                    type: integer
-                    description: The gregorian calendar year of the release.
-                  release:
-                    type: integer
-                    description: The sequence number of the release for that year, starting with 1.
-                    minimum: 1
-                  patch:
-                    type: integer
-                    description: The patch level of the release, starting with 0.
-                    minimum: 0
-              examples:
-                '2022.3':
-                  value:
-                    string: '2022.3'
-                    year: 2022
-                    release: 3
-                    patch: 0
-                2022.3.1:
-                  value:
-                    string: 2022.3.1
-                    year: 2022
-                    release: 3
-                    patch: 1
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-components:
-  securitySchemes:
-    GradleEnterpriseAccessKey:
-      type: http
-      scheme: bearer
-      bearerFormat: Bearer <<Gradle Enterprise Access Key>>
-      description: |
-        All requests require a Gradle Enterprise access key as a bearer token. 
-        Given an access key of `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required header is `Authorization: Bearer l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
-
-        Please consult the [Gradle Enterprise API User Manual](https://docs.gradle.com/enterprise/api-manual#access_control) for guidance on how to provision access keys and check user permissions.
-  responses:
-    BadRequestError:
-      description: The request cannot be fulfilled due to a problem.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            RequestValidationApiProblemResponse:
-              $ref: '#/components/examples/RequestValidationApiProblemExample'
-    NotFoundError:
-      description: The referenced resource either does not exist or the permissions to know about it are missing.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NotFoundResponse:
-              $ref: '#/components/examples/NotFoundApiProblemExample'
-    UnexpectedError:
-      description: The server encountered an unexpected error.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            UnexpectedErrorResponse:
-              $ref: '#/components/examples/UnexpectedErrorApiProblemExample'
-    NotReadyError:
-      description: The server is not ready to handle the request.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            IngestionNotCompletedResponse:
-              $ref: '#/components/examples/IngestionNotCompletedApiProblemExample'
-    NodeNotSignedInError:
-      description: The node was not signed in with Gradle Enterprise.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NodeNotSignedInResponse:
-              $ref: '#/components/examples/NodeNotSignedInProblemExample'
-    ForbiddenError:
-      description: The authenticated user has insufficient permissions.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            ForbiddenUserResponse:
-              $ref: '#/components/examples/ForbiddenUserExample'
-    UnauthorizedOrNotFoundError:
-      description: No API key was specified in the request, the key has been revoked or the user bearing the key lacks permissions for this operation.
-    BadRequest:
-      description: The request body is malformed or contains invalid values for at least one of the properties.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            CapabilityValidationProblemResponse:
-              $ref: '#/components/examples/CapabilityValidationProblemExample'
-  schemas:
-    ApiProblem:
-      type: object
-      description: |
-        Response detailing why a request was rejected.
-        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807) standard (colloquially known as "Problem JSON") for the response format.
-      required:
-        - type
-        - title
-        - status
-      properties:
-        status:
-          type: integer
-          description: HTTP status code of the problem response.
-        type:
-          type: string
-          description: A URN (Uniform Resource Name) identifying the type of the problem.
-        title:
-          type: string
-          description: The underlying reason for the problem.
-        detail:
-          type: string
-          description: A longer and comprehensive description of the problem. May be `null` if not available.
-          x-nullable: true
-    Build:
-      type: object
-      description: A build with the common attributes of a Build Scan.
-      required:
-        - id
-        - availableAt
-        - buildToolType
-        - buildToolVersion
-        - buildAgentVersion
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        availableAt:
-          type: integer
-          format: int64
-          description: A unix-epoch-time in milliseconds referring to the instant that Gradle Enterprise completed receiving and processing the build.
-        buildToolType:
-          type: string
-          description: The build tool type used to capture the Build Scan.
-        buildToolVersion:
-          type: string
-          description: The build tool version used.
-        buildAgentVersion:
-          type: string
-          description: The build agent version used.
-    Builds:
-      type: array
-      items:
-        $ref: '#/components/schemas/Build'
-      description: List of builds with the common attributes of a Build Scan.
-    BuildQuery:
-      type: object
-      properties:
-        availabilityWaitTimeoutSecs:
-          type: integer
-          minimum: 0
-          description: The time in seconds the server should wait for ingestion before returning a wait timeout response.
-    BuildAttributesValue:
-      type: object
-      description: A Build Scan value.
-      required:
-        - name
-      properties:
-        name:
-          type: string
-          description: The name of the Build Scan value.
-        value:
-          type: string
-          description: The value of the Build Scan value. May be `null` if the Build Scan value is not set.
-    BuildAttributesLink:
-      type: object
-      description: A Build Scan link.
-      required:
-        - label
-        - url
-      properties:
-        label:
-          type: string
-          description: The label of the Build Scan link.
-        url:
-          type: string
-          description: The url  of the Build Scan link.
-    GradleGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: Whether build logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-        taskInputsFileCapturingEnabled:
-          type: boolean
-          description: Whether task input file snapshots capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: Whether test logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-    GradleBuildOptions:
-      type: object
-      description: Gradle build options for this build.
-      required:
-        - configurationOnDemandEnabled
-        - continuousBuildEnabled
-        - continueOnFailureEnabled
-        - daemonEnabled
-        - dryRunEnabled
-        - maxNumberOfGradleWorkers
-        - offlineModeEnabled
-        - parallelProjectExecutionEnabled
-        - refreshDependenciesEnabled
-        - rerunTasksEnabled
-      properties:
-        buildCacheEnabled:
-          type: boolean
-          description: Whether the build cache was enabled for the build. May be `null` if Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version is < `1.3`. See https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
-          x-nullable: true
-        configurationCacheEnabled:
-          type: boolean
-          description: Whether the configuration cache was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/configuration_cache.html.
-          x-nullable: true
-        configurationOnDemandEnabled:
-          type: boolean
-          description: Whether configuration on demand mode was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
-        continuousBuildEnabled:
-          type: boolean
-          description: Whether continuous build mode was running for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
-        continueOnFailureEnabled:
-          type: boolean
-          description: Whether continue on failure mode was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
-        daemonEnabled:
-          type: boolean
-          description: Whether the build was run with the Gradle Daemon. See https://docs.gradle.org/current/userguide/gradle_daemon.html.
-        dryRunEnabled:
-          type: boolean
-          description: Whether the dry run flag was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
-        fileSystemWatchingEnabled:
-          type: boolean
-          description: Whether file system watching was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/file_system_watching.html.
-          x-nullable: true
-        maxNumberOfGradleWorkers:
-          type: integer
-          description: The maximum number of build workers used to run the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
-        offlineModeEnabled:
-          type: boolean
-          description: Whether the offline mode was set for the build. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
-        parallelProjectExecutionEnabled:
-          type: boolean
-          description: Whether parallel project execution was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
-        refreshDependenciesEnabled:
-          type: boolean
-          description: Whether the build was set to refresh all dependencies in the dependency cache. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
-        rerunTasksEnabled:
-          type: boolean
-          description: Whether the build was forced to run all the tasks, ignoring any up-to-date checks. https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
-    BuildAttributesEnvironment:
-      type: object
-      description: The environment where the build has been executed.
-      required:
-        - operatingSystem
-        - numberOfCpuCores
-        - jreVersion
-        - jvmVersion
-        - jvmMaxMemoryHeapSize
-        - jvmLocale
-      properties:
-        username:
-          type: string
-          description: Operating system username of the build user. May be `null` if no username was captured.
-          x-nullable: true
-        operatingSystem:
-          type: string
-          description: Operating system of the build machine.
-        numberOfCpuCores:
-          type: integer
-          description: Number of cores available to the build JVM.
-        jreVersion:
-          type: string
-          description: Version of the Java runtime that executed the build.
-        jvmVersion:
-          type: string
-          description: Version of the Java Virtual Machine that executed the build.
-        jvmMaxMemoryHeapSize:
-          type: integer
-          format: int64
-          description: Maximum heap memory available to the build JVM in bytes.
-        jvmCharset:
-          type: string
-          description: The default charset of the JVM that executed the build. May be `null` if capturing was not possible.
-          x-nullable: true
-        jvmLocale:
-          type: string
-          description: The locale of the JVM that executed the build.
-        publicHostname:
-          type: string
-          description: The hostname of the build machine, as seen on the network. May be `null` if capturing was not possible.
-          x-nullable: true
-        localHostname:
-          type: string
-          description: The hostname of the build machine, as specified by itself. May be `null` if capturing was not possible.
-          x-nullable: true
-        localIpAddresses:
-          type: array
-          items:
-            type: string
-          description: The local IP addresses of the build machine. May be `null` if capturing was not possible.
-          x-nullable: true
-    GradleAttributes:
-      type: object
-      description: The attributes of a Gradle Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - gradleVersion
-        - pluginVersion
-        - requestedTasks
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        gradleVersion:
-          type: string
-          description: The Gradle version used.
-        pluginVersion:
-          type: string
-          description: The Gradle Enterprise Gradle plugin version used.
-        rootProjectName:
-          type: string
-          description: The root project name. May be `null` in case of very early build failure.
-          x-nullable: true
-        requestedTasks:
-          type: array
-          items:
-            type: string
-          description: The list of requested tasks.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/GradleGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/GradleBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    MavenGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.6`. See https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: Whether to capture build logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-        goalInputsFileCapturingEnabled:
-          type: boolean
-          description: Whether to capture goal input file snapshots for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.1`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: Whether to capture test logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-    MavenBuildOptions:
-      type: object
-      description: Maven build options for this build.
-      required:
-        - errorsEnabled
-        - maxNumberOfThreads
-        - nonRecursiveEnabled
-        - noSnapshotsUpdatesEnabled
-        - offlineModeEnabled
-        - updateSnapshotsEnabled
-      properties:
-        batchModeEnabled:
-          type: boolean
-          description: Whether the build was configured to run in non-interactive (batch) mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
-          x-nullable: true
-        debugEnabled:
-          type: boolean
-          description: Whether the build was configured to produce execution debug output. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
-          x-nullable: true
-        errorsEnabled:
-          type: boolean
-          description: Whether the build was configured to produce execution error messages. See https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
-        failAtEndEnabled:
-          type: boolean
-          description: Whether the build was configured to only fail at the end. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
-          x-nullable: true
-        failFastEnabled:
-          type: boolean
-          description: Whether the build was configured to fail at the first error. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
-          x-nullable: true
-        failNeverEnabled:
-          type: boolean
-          description: Whether the build was configured to never fail, regardless of errors produced. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
-          x-nullable: true
-        laxChecksumsEnabled:
-          type: boolean
-          description: Whether the build was configured to only warn if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
-          x-nullable: true
-        maxNumberOfThreads:
-          type: integer
-          description: Maximum number of threads used when executing the build. See https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
-        nonRecursiveEnabled:
-          type: boolean
-          description: Whether the build was configured to not recurse into sub-projects. See https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
-        rerunGoals:
-          type: boolean
-          description: Whether the build was configured to rerun goals without checking the build cache. May be `null` if Gradle Enterprise Maven extension version is < `1.13`. See https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
-          x-nullable: true
-        noSnapshotsUpdatesEnabled:
-          type: boolean
-          description: Whether the build was configured to suppress snapshot updates. See https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
-        offlineModeEnabled:
-          type: boolean
-          description: Whether the build was configured to run offline. See https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
-        quietEnabled:
-          type: boolean
-          description: Whether the build was configured to run in quiet mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
-          x-nullable: true
-        strictChecksumsEnabled:
-          type: boolean
-          description: Whether the build was configured to fail if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
-          x-nullable: true
-        updateSnapshotsEnabled:
-          type: boolean
-          description: Whether the build was configured to force a check for missing releases and updated snapshots on remote repositories. See https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
-    MavenAttributes:
-      type: object
-      description: The attributes of a Maven Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - mavenVersion
-        - extensionVersion
-        - requestedGoals
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        mavenVersion:
-          type: string
-          description: The Maven version used.
-        extensionVersion:
-          type: string
-          description: The Gradle Enterprise Maven extension version used.
-        topLevelProjectName:
-          type: string
-          description: The top level project name. May be `null` in case of very early build failure.
-          x-nullable: true
-        requestedGoals:
-          type: array
-          items:
-            type: string
-          description: The list of requested goals.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/MavenGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/MavenBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    GradleBuildCachePerformanceTaskExecutionEntry:
-      type: object
-      required:
-        - taskPath
-        - taskType
-        - avoidanceOutcome
-        - duration
-      properties:
-        taskPath:
-          type: string
-          description: The full task path.
-        taskType:
-          type: string
-          description: The fully qualified class name of the task.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_up_to_date
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - lifecycle
-            - no-source
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_up_to_date` - Task whose execution was avoided due to build incrementalism
-              * `avoided_from_local_cache` - Task whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Task whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Task which was executed but was cacheable
-              * `executed_not_cacheable` - Task which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Task which was executed and whose cacheability could not be determined
-              * `lifecycle` - Lifecycle task
-              * `no-source` - No-source task
-              * `skipped` - Skipped task
-        duration:
-          type: integer
-          format: int64
-          description: The task duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: The task fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the task was not fingerprinted, or the information was not available.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: The task avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_not_enabled
-            - cache-if_condition_not_matched
-            - disabled_to_ensure_correctness
-            - do-not-cache-if_condition_matched
-            - multiple_outputs_declared
-            - no_outputs_declared
-            - non_cacheable_inputs
-            - non_cacheable_task_action
-            - non_cacheable_task_implementation
-            - non_cacheable_tree_output
-            - overlapping_outputs
-            - task_has_no_actions
-            - task_output_caching_not_enabled
-            - unknown
-          description: |
-            The category of the non-cacheability reason:
-              * `build_cache_not_enabled` - Caching has not been enabled for the build
-              * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
-              * `disabled_to_ensure_correctness` - The task failed validation. Available since Gradle 7.0
-              * `do-not-cache-if_condition_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#doNotCacheIf`
-              * `multiple_outputs_declared` - The task declared multiple outputs
-              * `no_outputs_declared` - The task had no outputs declared
-              * `non_cacheable_inputs` - One of the task inputs was not cacheable, either because some type used as an input to the task was loaded via a custom classloader, or a Java lambda was used as an input. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_action` - One of the task actions was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_implementation` - The task implementation was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_tree_output` - The task had a `org.gradle.api.file.FileTree` or a `org.gradle.api.internal.file.collections.DirectoryFileTree` as an output. Available since Gradle 5.0
-              * `overlapping_outputs` - The tasks outputs overlapped with another task. As Gradle cannot safely determine which task each output file belongs to, it disabled caching            
-              * `task_has_no_actions` - The task did not declare any actions
-              * `task_output_caching_not_enabled` - Caching has not been enabled for the task
-              * `unknown` - Reason for disabled caching was not known
-
-            May be `null` when the task was cacheable or if the information was not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: The human-readable reason for a non-cacheable task. May be `null` when the task was cacheable or if the information was not available.
-          x-nullable: true
-        skipReasonMessage:
-          type: string
-          description: The detailed reason why the task was skipped. May be `null` if the task was not skipped or Gradle versions <7.6 are used.
-          x-nullable: true
-    GradleBuildCachePerformanceTaskExecution:
-      type: array
-      description: A list of executed tasks with performance related information.
-      items:
-        $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
-    GradleBuildCachePerformanceTaskFingerprintingSummary:
-      type: object
-      description: A summary of task fingerprinting. Fingerprinted tasks are part of the `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
-      x-nullable: true
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted tasks.
-        serialDuration:
-          type: integer
-          format: int64
-          description: Sum of all fingerprinting times of fingerprinted tasks in milliseconds.
-    GradleBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - upToDate
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
-        upToDate:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to build incrementalism in milliseconds.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the local build cache in milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the remote build cache in milliseconds.
-    GradleBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: Information about the local build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the local build cache was enabled.  May be `null` if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the local cache was disabled due to an error occuring in loading or storing local build cache entries.
-        directory:
-          type: string
-          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: Information about the remote build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        type:
-          type: string
-          description: The type of the connector used to communicate with the remote build cache. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        className:
-          type: string
-          description: The class name of the connector. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: URL of the remote build cache. May be `null` if the remote build cache is disabled or if the given type is not supported or it doesn't have the concept of a URL.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    GradleBuildCachePerformanceBuildCaches:
-      type: object
-      description: Information about the local and remote build caches used in the build. May be `null` if the build cache is globally disabled.
-      x-nullable: true
-      required:
-        - local
-        - remote
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheOverhead'
-    GradleBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Gradle Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveTaskExecutionTime
-        - serialTaskExecutionTime
-        - serializationFactor
-        - taskExecution
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveTaskExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time spent executing tasks in milliseconds. It is the time spent between the start of the first task in the execution phase and the end of the last task of the execution phase, removing any interval where no task is being executed.
-        serialTaskExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time of all task executions in milliseconds. It is the sum of all individual task durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: The ratio of `serialTaskExecutionTime` over the `effectiveTaskExecutionTime`. Quantifies the effect of task parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that tasks were executed faster due to parallelization.
-        taskExecution:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
-        taskFingerprintingSummary:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary'
-        avoidanceSavingsSummary:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary'
-        buildCaches:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
-    MavenBuildCachePerformanceGoalExecutionEntry:
-      type: object
-      required:
-        - goalName
-        - mojoType
-        - goalExecutionId
-        - goalProjectName
-        - avoidanceOutcome
-        - duration
-      properties:
-        goalName:
-          type: string
-          description: The goal name.
-        mojoType:
-          type: string
-          description: The fully qualified class name of the Mojo that provides the implementation of this goal.
-        goalExecutionId:
-          type: string
-          description: The goal execution ID.
-        goalProjectName:
-          type: string
-          description: The goal project name.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_from_local_cache` - Goal whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Goal whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Goal which was executed but was cacheable
-              * `executed_not_cacheable` - Goal which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Goal which was executed and whose cacheability could not be determined
-              * `skipped` - Skipped goal
-        duration:
-          type: integer
-          format: int64
-          description: The goal duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: The goal fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the goal was not fingerprinted.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: The goal avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_disabled_by_user
-            - goal_execution_marked_non_cacheable
-            - goal_not_supported
-            - no_gradle_enterprise_server_configured
-            - non_clean_build
-            - not_entitled
-            - offline_build
-            - unknown
-            - unknown_entitlements
-          description: |
-            The category of the non-cacheability reason:
-              * `build_cache_disabled_by_user` - The build cache was disabled by the user
-              * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
-              * `goal_not_supported` - The goal did not support build caching
-              * `no_gradle_enterprise_server_configured` - No Gradle Enterprise server was configured
-              * `non_clean_build` - The `clean` lifecycle was not executed 
-              * `not_entitled` - The Gradle Enterprise license entitlements did not allow Maven build caching
-              * `offline_build` - The build was run in offline mode
-              * `unknown` - Reason for disabled caching was not known
-              * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
-
-            May be `null` when the goal execution was cacheable or if the information was not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: The human-readable reason for a non-cacheable goal execution. May be `null` when the goal execution was cacheable or if the information was not available.
-          x-nullable: true
-    MavenBuildCachePerformanceGoalExecution:
-      type: array
-      description: A list of executed goals with performance related information.
-      items:
-        $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
-    MavenBuildCachePerformanceGoalFingerprintingSummary:
-      type: object
-      description: A summary of goal fingerprinting. Fingerprinted goals are part of the `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted goals.
-        serialDuration:
-          type: integer
-          format: int64
-          description: Sum of all fingerprinting times of fingerprinted goals in milliseconds.
-    MavenBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the local build cache in milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the remote build cache in milliseconds.
-    MavenBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: Information about the local build cache used in the build, if it was configured in the build. May be `null` if the local build cache is not configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the local build cache was enabled. May be `null` if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the local cache was disabled due to an error occurring in loading or storing local build cache entries.
-        directory:
-          type: string
-          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: Information about the remote build cache used in the build, if it was configured in the build. May be `null` if the remote build cache is not configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: URL of the remote build cache. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    MavenBuildCachePerformanceBuildCaches:
-      type: object
-      description: Information about the local and remote build caches used in the build, if it was configured in the build. May be `null` if the build cache configuration could not be captured (e.g. very early build failure).
-      x-nullable: true
-      required:
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheOverhead'
-    MavenBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Maven Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveProjectExecutionTime
-        - serialProjectExecutionTime
-        - serializationFactor
-        - goalExecution
-        - goalFingerprintingSummary
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveProjectExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time spent executing projects in milliseconds. It is the time spent between the start of the first project execution and the end of the last project execution, removing any interval where no project is being executed.
-        serialProjectExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time of all project executions in milliseconds. It is the sum of all individual project durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: The ratio of `serialProjectExecutionTime` over the `effectiveProjectExecutionTime`. Quantifies the effect of project parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that projects were executed faster due to parallelization.
-        goalExecution:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
-        goalFingerprintingSummary:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary'
-        avoidanceSavingsSummary:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary'
-        buildCaches:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
-    GradleProject:
-      type: object
-      description: A Gradle project.
-      required:
-        - name
-        - path
-      properties:
-        name:
-          type: string
-          description: The name of the project.
-        path:
-          type: string
-          description: The path of the project.
-        parent:
-          type: integer
-          x-nullable: true
-          description: The index of the parent of this Gradle project in the GradleProjects array. May be `null` if this project has no parent (i.e. root project of a build).
-    GradleProjects:
-      type: array
-      items:
-        $ref: '#/components/schemas/GradleProject'
-      description: List of Gradle projects including structural relationships.
-    MavenModule:
-      type: object
-      description: A Maven module.
-      required:
-        - name
-        - groupId
-        - artifactId
-        - version
-      properties:
-        name:
-          type: string
-          description: The name of the module.
-        groupId:
-          type: string
-          description: The group ID of the module.
-        artifactId:
-          type: string
-          description: The artifact ID of the module.
-        version:
-          type: string
-          description: The version of the module.
-        parent:
-          type: integer
-          x-nullable: true
-          description: The index of the parent of this Maven module in the MavenModules array. May be `null` if this module has no parent (i.e. top level project).
-    MavenModules:
-      type: array
-      items:
-        $ref: '#/components/schemas/MavenModule'
-      description: List of Maven modules including structural relationships.
-    ReplicationConfiguration:
-      description: Cached data replication configuration description. May be `null` if replication is not configured.
-      type: object
-      x-nullable: true
-      required:
-        - source
-        - preemptive
-      properties:
-        source:
-          type: string
-          description: The name of the Build Cache Node which is the source of data.
-        preemptive:
-          type: boolean
-          description: Indicates if preemptive replication is enabled from the source.
-    NodeConfiguration:
-      description: A Build Cache Node configuration description.
-      type: object
-      required:
-        - enabled
-      properties:
-        enabled:
-          type: boolean
-          description: Indicates if the Build Cache Node is enabled.
-        replication:
-          $ref: '#/components/schemas/ReplicationConfiguration'
-    KeySecretPair:
-      description: A Build Cache Node key and secret pair.
-      type: object
-      required:
-        - key
-        - secret
-      properties:
-        key:
-          type: string
-          description: A unique identifier for the Build Cache Node in Gradle Enterprise.
-        secret:
-          type: string
-          description: The secret associated with the Build Cache Node.
-    TestDistributionAgentPoolId:
-      description: The unique identifier of the Agent Pool.
-      type: string
-      minLength: 8
-      maxLength: 8
-      pattern: ^[a-z2-7]{8}$
-    TestDistributionAgentPoolConfigurationWithId:
-      description: An Agent Pool configuration.
-      type: object
-      required:
-        - id
-        - name
-        - minimumSize
-        - maximumSize
-        - capabilities
-        - orderIndex
-      properties:
-        id:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-          example: functional-test-agents
-        minimumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        maximumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        orderIndex:
-          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
-          type: integer
-          format: int32
-          minimum: 0
-        capabilities:
-          type: array
-          items:
-            type: string
-            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
-          example:
-            - jdk=17
-            - os=linux
-            - functional-test
-    TestDistributionAgentPoolPage:
-      description: A list of Agent Pools.
-      type: object
-      required:
-        - content
-      properties:
-        content:
-          type: array
-          description: A list of Agent Pool IDs.
-          items:
-            $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-    TestDistributionAgentPoolConfiguration:
-      description: An Agent Pool configuration.
-      type: object
-      required:
-        - name
-        - minimumSize
-        - maximumSize
-        - capabilities
-      properties:
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-          example: functional-test-agents
-        minimumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        maximumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        orderIndex:
-          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
-          type: integer
-          format: int32
-          x-nullable: true
-          minimum: 0
-        capabilities:
-          type: array
-          items:
-            type: string
-            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
-          example:
-            - jdk=17
-            - os=linux
-            - functional-test
-    TestDistributionAgentPoolStatus:
-      description: The status of an Agent Pool.
-      type: object
-      required:
-        - id
-        - name
-        - minimumSize
-        - maximumSize
-        - connectedAgents
-        - idleAgents
-        - desiredAgents
-      properties:
-        id:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-        minimumSize:
-          type: integer
-          format: int32
-        maximumSize:
-          type: integer
-          format: int32
-        connectedAgents:
-          type: integer
-          format: int32
-        idleAgents:
-          type: integer
-          format: int32
-        desiredAgents:
-          type: integer
-          format: int32
-    TestDistributionApiKeyPrefix:
-      description: A Test Distribution Agent API key prefix.
-      type: object
-      required:
-        - keyPrefix
-        - generatedAt
-      properties:
-        keyPrefix:
-          type: string
-          minLength: 26
-          maxLength: 26
-          pattern: ^[a-z2-7]{26}$
-          description: The Agent API key.
-        generatedAt:
-          type: string
-          format: date-time
-        lastUsedAt:
-          type: string
-          format: date-time
-          x-nullable: true
-        revokedAt:
-          type: string
-          format: date-time
-          x-nullable: true
-    TestDistributionApiKeyPrefixPage:
-      description: A list of Test Distribution Agent API key prefixes.
-      type: object
-      required:
-        - content
-      properties:
-        content:
-          type: array
-          items:
-            $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-    TestDistributionApiKey:
-      description: A Test Distribution Agent API key.
-      type: object
-      required:
-        - key
-      properties:
-        key:
-          type: string
-          minLength: 52
-          maxLength: 52
-          pattern: ^[a-z2-7]{52}$
-          description: The Agent API key.
-  examples:
-    RequestValidationApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:validation
-        title: Request validation failed.
-        detail: |
-          Numeric instance is lower than the required minimum (minimum: 1, found: 0) (Additional info: Query parameter: maxWaitSecs).
-        status: 400
-    NotFoundApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:not-found
-        title: The requested resource is not found or the permissions to know about it are missing.
-        status: 404
-    UnexpectedErrorApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:unexpected-error
-        title: Encountered an internal server error.
-        detail: |
-          The ingestion of build 9r4d13f0r3v3r failed.
-        status: 500
-    IngestionNotCompletedApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-processing-incomplete
-        title: Build processing is incomplete.
-        detail: |
-          The data of build 9r4d13f0r3v3r is not yet available for viewing. Please try again later.
-        status: 503
-    NodeNotSignedInProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:node-not-signed-in
-        title: Node with name not-signed-in-node1 must be signed-in before this operation can be performed.
-        status: 503
-    ForbiddenUserExample:
-      value:
-        type: urn:gradle:enterprise:forbidden
-        title: Insufficient permissions
-        detail: User must have Test Distribution administration permission to access this endpoint.
-        status: 403
-    CapabilityValidationProblemExample:
-      value:
-        type: urn:gradle:enterprise:validation
-        title: Invalid request parameters
-        detail: One or more capabilities have an invalid format.
-        status: 400
-tags:
-  - name: Builds
-    description: |
-      Endpoints related to retrieving details of a Build Scan of the Gradle Enterprise instance. 
-      To access these endpoints the user requires the `Access build data via the API` permission.
-  - name: BuildCache
-    x-displayName: Build Cache
-    description: |
-      Endpoints related to configuring the Build Cache nodes of the Gradle Enterprise instance. 
-      To access these endpoints the user requires the `Configure build caches` permission.
-  - name: Meta
-    x-displayName: Meta
-    description: |
-      Endpoints related to the Gradle Enterprise installation and its state.
-  - name: GradleEnterprise
-    x-traitTag: true
-    description: All endpoints of the Gradle Enterprise API.
-  - name: TestDistribution
-    x-displayName: Test Distribution
-    description: |
-      Endpoints related to the management of Test Distribution resources.
-      To access these endpoints the user requires the `Admin` permission.

From 4f20d4de0b2f3e83ddf419a2b22b8d5cf3308561 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:01:40 +0200
Subject: [PATCH 15/57] Make classes final

---
 .../gradle/enterprise/loader/OfflineBuildScanDataLoader.java   | 3 ++-
 .../enterprise/loader/ReflectiveBuildScanDumpReader.java       | 3 ++-
 .../gradle/enterprise/loader/OnlineBuildScanDataLoader.java    | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index 77074f77..e3edb7a8 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -9,7 +9,8 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-public class OfflineBuildScanDataLoader implements BuildScanDataLoader {
+public final class OfflineBuildScanDataLoader implements BuildScanDataLoader {
+
     private final ReflectiveBuildScanDumpReader reader;
 
     private OfflineBuildScanDataLoader(ReflectiveBuildScanDumpReader reader) {
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index 3b1b15c2..6116b503 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -11,7 +11,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 
-public class ReflectiveBuildScanDumpReader {
+public final class ReflectiveBuildScanDumpReader {
 
     private final Object buildScanDumpReader;
 
@@ -78,4 +78,5 @@ public static void main(String[] args) {
         Pair<GradleAttributes, GradleBuildCachePerformance> result = extractor.readGradleBuildScanDump(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise-gradle-build-validation/.data/02-validate-local-build-caching-same-location/20230511T111441-645cb201/second-build_ge-solutions/sample-projects/gradle/8.x/no-ge/build-scan-8.0.2-3.12.6-1683796487697-104c8ac5-cf01-4eb6-8b2d-f447d4803249.scan"));
         System.out.println("Successfully fetched build scan dump data: " + result);
     }
+
 }
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 57a77e82..803c13f9 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -7,7 +7,7 @@
 
 import java.net.URI;
 
-public class OnlineBuildScanDataLoader implements BuildScanDataLoader {
+public final class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
     @Override
     public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {

From 141434e2a9b00146027defdacf12bb10ae0c2291 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:18:11 +0200
Subject: [PATCH 16/57] Only run the OpenAPI generator at build time in the api
 module

---
 .../build.gradle.kts                          |   19 +-
 .../build.gradle.kts                          |   62 -
 .../src/main/openapi/openapi.yaml             | 2553 -----------------
 3 files changed, 8 insertions(+), 2626 deletions(-)
 delete mode 100644 components/build-scan-data-loader-online/src/main/openapi/openapi.yaml

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 50fe5fa2..8ba0d4e8 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -35,8 +35,14 @@ dependencies {
 
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")
+    implementation("com.squareup.okhttp3:okhttp-tls")
+    implementation("com.squareup.okhttp3:logging-interceptor")
+
+    implementation("io.swagger:swagger-annotations:1.6.10")
     implementation("io.gsonfire:gson-fire:1.8.5")
+    implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
+
     implementation("javax.annotation:javax.annotation-api:1.3.2")
     implementation("com.google.code.findbugs:jsr305:3.0.2")
 }
@@ -53,8 +59,8 @@ openApiGenerate {
     inputSpec.set(providers.provider { openApiSpec.singleFile.absolutePath })
     outputDir.set("$buildDir/generated/gradle_enterprise_api")
     ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
-    modelPackage.set("com.gradle.enterprise.api.model")
     apiPackage.set("com.gradle.enterprise.api")
+    modelPackage.set("com.gradle.enterprise.api.model")
     invokerPackage.set("com.gradle.enterprise.api.client")
 
     // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
@@ -70,19 +76,10 @@ openApiGenerate {
     ))
 }
 
-val filterOpenApiGeneratedClasses by tasks.registering(Copy::class) {
-    from(tasks.openApiGenerate) {
-        include("com/gradle/enterprise/api/client/JSON.java")
-        include("com/gradle/enterprise/api/client/ApiException.java")
-        include("com/gradle/enterprise/api/model/**/*")
-    }
-    into(layout.buildDirectory.dir("generated-filtered"))
-}
-
 sourceSets {
     main {
         java {
-            srcDir(filterOpenApiGeneratedClasses)
+            srcDir(tasks.openApiGenerate)
         }
     }
 }
diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
index 4bf9706f..ff225483 100644
--- a/components/build-scan-data-loader-online/build.gradle.kts
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -1,73 +1,11 @@
 plugins {
     id("java-library")
-    id("org.openapi.generator") version "6.6.0"
-}
-
-val gradleEnterpriseVersion = "2022.4"
-val apiUrl = "https://docs.gradle.com/enterprise/api-manual/ref/gradle-enterprise-$gradleEnterpriseVersion-api.yaml"
-val apiSpecificationFile = objects.property(File::class).value(resources.text.fromUri(apiUrl).asFile()).map { file -> file.absolutePath }
-
-repositories {
-    mavenCentral()
 }
 
 dependencies {
     api(project(":build-scan-data-loader-api"))
-
-    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
-    implementation("com.squareup.okhttp3:okhttp")
-    implementation("com.squareup.okhttp3:okhttp-tls")
-    implementation("com.squareup.okhttp3:logging-interceptor")
-
-    implementation("io.swagger:swagger-annotations:1.6.10")
-    implementation("io.gsonfire:gson-fire:1.8.5")
-    implementation("javax.ws.rs:jsr311-api:1.1.1")
-    implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
-
-    implementation("javax.annotation:javax.annotation-api:1.3.2")
-    implementation("com.google.code.findbugs:jsr305:3.0.2")
-}
-
-openApiGenerate {
-    generatorName.set("java")
-    inputSpec.set(apiSpecificationFile)
-    outputDir.set("$buildDir/generated/gradle_enterprise_api")
-    ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
-    modelPackage.set("com.gradle.enterprise.api.model")
-    apiPackage.set("com.gradle.enterprise.api")
-    invokerPackage.set("com.gradle.enterprise.api.client")
-
-    // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
-    configOptions.set(mapOf(
-        "library" to "okhttp-gson",
-        "dateLibrary" to "java8",
-        "hideGenerationTimestamp" to "true",
-        "openApiNullable" to "false",
-        "useBeanValidation" to "false",
-        "disallowAdditionalPropertiesIfNotPresent" to "false",
-        "containerDefaultToNull" to "true",
-        "sourceFolder" to ""
-    ))
-}
-
-val filterOpenApiGeneratedClasses by tasks.registering(Copy::class) {
-    from(tasks.openApiGenerate) {
-        include("com/gradle/enterprise/api/client/**/*")
-        exclude("com/gradle/enterprise/api/client/JSON.java")
-        exclude("com/gradle/enterprise/api/client/ApiException.java")
-    }
-    into(layout.buildDirectory.dir("generated-filtered"))
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir(filterOpenApiGeneratedClasses)
-        }
-    }
-}
-
-
 java {
     toolchain {
         languageVersion.set(JavaLanguageVersion.of(8))
diff --git a/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml b/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml
deleted file mode 100644
index 8d7bfb30..00000000
--- a/components/build-scan-data-loader-online/src/main/openapi/openapi.yaml
+++ /dev/null
@@ -1,2553 +0,0 @@
-openapi: 3.0.3
-info:
-  title: Gradle Enterprise API
-  description: |
-    The Gradle Enterprise API allows programmatic interaction with various aspects of Gradle Enterprise, from configuration to inspecting build data.
-  version: "2022.4"
-  license:
-    name: Gradle Enterprise License
-    url: https://gradle.com/legal/gradle-enterprise-software-agreement
-  termsOfService: https://gradle.com/legal/terms-of-service
-  contact:
-    name: Gradle
-    url: https://gradle.com
-  x-logo:
-    url: https://assets.gradle.com/logo/gradle-enterprise-dark-green-primary.svg
-    altText: Gradle Enterprise
-servers:
-  - url: https://ge.mycompany.com
-    description: Your Gradle Enterprise instance.
-security:
-  - GradleEnterpriseAccessKey: []
-paths:
-  /api/builds:
-    description: |
-      Returns a list of builds with the common attributes of a Build Scan.
-      The returned list is capped by the `maxBuilds` and `maxWaitSecs` query parameters.
-      This endpoint supports pagination by using the `fromBuild` or `sinceBuild` query parameters, and the last returned build from a previous call to one of these endpoints.
-    parameters:
-      - in: query
-        name: BuildsQuery
-        explode: true
-        description: The query parameters used to retrieve the list of builds.
-        schema:
-          title: BuildsQuery
-          type: object
-          properties:
-            since:
-              type: integer
-              format: int64
-              minimum: 0
-              x-nullable: true
-              description: |
-                **This parameter is deprecated, use `fromInstant` instead.**
-                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant.
-                This parameter can only be used with `reverse=false`.
-                Therefore, a value of `0` will process all builds.
-                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
-                This parameter has no effect if any of `sinceBuild`, `fromInstant`, `fromBuild` are used.
-              deprecated: true
-            sinceBuild:
-              type: string
-              x-nullable: true
-              description: |
-                **This parameter is deprecated, use `fromBuild` instead.**
-                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it).
-                This parameter can only be used with `reverse=false`.
-                This parameter has precedence over any value set for the `since` parameter.
-                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
-                A Build Scan ID for a deleted build is valid.
-                This parameter has no effect if any of `fromInstant`, `fromBuild` are used.
-              deprecated: true
-            fromInstant:
-              type: integer
-              format: int64
-              minimum: 0
-              x-nullable: true
-              description: |
-                A unix-epoch-time in milliseconds allowing to retrieve builds for which Gradle Enterprise completed receiving and processing the build after this instant when used in conjunction with `reverse=false`, or before this instant when used in conjunction with `reverse=true`.
-                Therefore, a value of `0` will process all builds.
-                If not provided, the time in milliseconds when the request is received by the Gradle Enterprise instance will be used.
-                This parameter has no effect if `fromBuild` is used.
-            fromBuild:
-              type: string
-              x-nullable: true
-              description: |
-                A Build Scan ID allowing to retrieve builds for which Gradle Enterprise completed receiving and processing after the given Build Scan ID (excluding it) when used in conjunction with `reverse=false`, or before the given Build Scan ID (excluding it) when used in conjunction with `reverse=true`.
-                This parameter has precedence over any value set for the `since`, `sinceBuild`, `fromInstant` parameters.
-                A valid Build Scan ID must be provided, that is, a Build Scan ID that exists in the Gradle Enterprise instance.
-                A Build Scan ID for a deleted build is valid.
-            reverse:
-              type: boolean
-              x-nullable: true
-              description: |
-                A boolean indicating the time direction of the query.
-                A value of `true` indicates a backward query, and returned builds will be sorted from most to least recent.
-                A value of `false` indicates a forward query, and returned builds will be sorted from least to most recent.
-                This parameter has no effect if any of `since`, `sinceBuild` are used.
-                If not provided, the default value is `false`.
-            maxBuilds:
-              type: integer
-              minimum: 0
-              maximum: 1000
-              x-nullable: true
-              description: |
-                The maximum number of builds returned by the query.
-                The query returns when that number is reached or when `maxWaitSecs` is reached.
-                If not provided, the default value is `100`.
-            maxWaitSecs:
-              type: integer
-              minimum: 1
-              maximum: 20
-              x-nullable: true
-              description: |
-                The maximum number of seconds to wait for builds before returning.
-                If this time is reached before `maxBuilds` is reached, the query returns with the already processed builds.
-                Note that this time is respected with best effort.
-                A query will return soon after this time has passed but there is no guarantee that it exactly returns before this time has passed.
-                This parameter has no effect if `reverse=true` is specified, because new builds cannot become available in the past.
-                If not provided, the default value is `3`.
-    get:
-      operationId: GetBuilds
-      summary: Get a list of builds with the common attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: A list of builds with the common attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Builds'
-              example:
-                - id: 9r4d13f0r3v3r
-                  availableAt: 1635400481000
-                  buildToolType: gradle
-                  buildToolVersion: '7.2'
-                  buildAgentVersion: 3.7.1
-                - id: ji7vz3ey5qdvk
-                  availableAt: 1635400482000
-                  buildToolType: maven
-                  buildToolVersion: 3.8.4
-                  buildAgentVersion: '1.13'
-                - id: cvpd4j7ug7j4q
-                  availableAt: 1635400483000
-                  buildToolType: bazel
-                  buildToolVersion: 6.0.0
-                  buildAgentVersion: '1.0'
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the common attributes of a Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetBuild
-      summary: Get the common attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The common attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Build'
-              example:
-                id: 9r4d13f0r3v3r
-                availableAt: 1635400481000
-                buildToolType: gradle
-                buildToolVersion: '7.2'
-                buildAgentVersion: 3.7.1
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the attributes of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleAttributes
-      summary: Get the attributes of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleAttributes'
-              example:
-                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:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  taskInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  buildCacheEnabled: true
-                  configurationCacheEnabled: true
-                  configurationOnDemandEnabled: true
-                  continuousBuildEnabled: true
-                  continueOnFailureEnabled: true
-                  daemonEnabled: true
-                  dryRunEnabled: true
-                  fileSystemWatchingEnabled: true
-                  maxNumberOfGradleWorkers: 4
-                  offlineModeEnabled: true
-                  parallelProjectExecutionEnabled: true
-                  refreshDependenciesEnabled: true
-                  rerunTasksEnabled: true
-                environment:
-                  username: gradle
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: gradle
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the attributes of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenAttributes
-      summary: Get the attributes of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenAttributes'
-              example:
-                id: 9r4d13f0r3v3r
-                buildStartTime: 1637316480
-                buildDuration: 11000
-                mavenVersion: 3.8.4
-                extensionVersion: 1.11.1
-                topLevelProjectName: example-project
-                requestedGoals:
-                  - clean
-                  - verify
-                hasFailed: false
-                tags:
-                  - CI
-                  - feature-branch
-                values:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  goalInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  batchModeEnabled: true
-                  debugEnabled: true
-                  errorsEnabled: true
-                  failAtEndEnabled: true
-                  failFastEnabled: true
-                  failNeverEnabled: true
-                  laxChecksumsEnabled: true
-                  maxNumberOfThreads: 4
-                  nonRecursiveEnabled: true
-                  noSnapshotsUpdatesEnabled: true
-                  offlineModeEnabled: true
-                  quietEnabled: true
-                  rerunGoals: false
-                  strictChecksumsEnabled: true
-                  updateSnapshotsEnabled: true
-                environment:
-                  username: maven
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: maven
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build cache performance of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleBuildCachePerformance
-      summary: Get the build cache performance of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveTaskExecutionTime: 5000
-                serialTaskExecutionTime: 10000
-                serializationFactor: 2
-                taskExecution:
-                  - taskPath: ':task'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - taskPath: ':task2'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                  - taskPath: ':task3'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    fingerprintingDuration: 6
-                    nonCacheabilityCategory: cache-if_condition_not_matched
-                    nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
-                  - taskPath: ':task4'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: skipped
-                    duration: 0
-                    fingerprintingDuration: 0
-                    skipReasonMessage: some skip reason message
-                taskFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  upToDate: 0
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    type: HTTP
-                    className: org.example.MyBuildCache
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build cache performance of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenBuildCachePerformance
-      summary: Get the build cache performance of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveProjectExecutionTime: 5000
-                serialProjectExecutionTime: 10000
-                serializationFactor: 2
-                goalExecution:
-                  - goalName: clean:clean
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-clean
-                    goalProjectName: myproject
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    nonCacheabilityCategory: build_cache_disabled_by_user
-                    nonCacheabilityReason: Neither the local or remote build cache were enabled in the configuration of the build.
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject2
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                goalFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-projects:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build structure of a Gradle Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleProjects
-      summary: Get the projects of a Gradle Build Scan.
-      description: This model is Gradle specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The projects of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleProjects'
-              example:
-                - name: root project
-                  path: ':'
-                - name: sub project
-                  path: ':sub'
-                  parent: 0
-                - name: included build root project
-                  path: ':included'
-                - name: included build sub project
-                  path: ':included:sub'
-                  parent: 2
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-modules:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        description: The query parameters used to retrieve the build structure of a Maven Build Scan.
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenModules
-      summary: Get the modules of a Maven Build Scan.
-      description: This model is Maven specific and cannot be requested for another build tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The modules of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenModules'
-              example:
-                - name: top level project
-                  groupId: com
-                  artifactId: top-level
-                  version: '1.0'
-                - name: sub project a
-                  groupId: com
-                  artifactId: sub-a
-                  version: '1.1'
-                  parent: 0
-                - name: sub project b
-                  groupId: com
-                  artifactId: sub-b
-                  version: '2.0'
-                  parent: 0
-                - name: sub project a 2
-                  groupId: com
-                  artifactId: sub-a-a
-                  version: 2.1-SNAPSHOT
-                  parent: 1
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/build-cache/nodes/{name}:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
-    get:
-      operationId: GetBuildCacheNode
-      summary: View the configuration of a Build Cache Node.
-      description: View the enablement status and replication configuration of a Build Cache Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The configuration of a Build Cache Node.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/NodeConfiguration'
-              example:
-                enabled: false
-                replication:
-                  source: parent-node-1
-                  preemptive: true
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-    put:
-      operationId: CreateOrUpdateBuildCacheNode
-      summary: Create or update a Build Cache Node.
-      description: |
-        Create a new Build Cache Node in Gradle Enterprise or update the configuration of an existing one.
-        The Built-in Build Cache Node cannot be named as the target of this operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/NodeConfiguration'
-            example:
-              enabled: false
-              replication:
-                source: parent-node-1
-                preemptive: true
-      responses:
-        '200':
-          description: The name referenced an existing Build Cache Node and that Build Cache Node’s configuration was updated successfully.
-        '201':
-          description: A new Build Cache Node was created with the configuration specified in the request.
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-  /api/build-cache/nodes/{name}/secret:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node.
-    post:
-      operationId: RegenerateSecretOfBuildCacheNode
-      summary: Regenerate the secret of a Build Cache Node.
-      description: |
-        Regenerates the secret associated with the named Build Cache Node. The old secret expires immediately, causing the Build Cache Node to
-        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot be named as the target of this operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The name referenced an existing Build Cache Node and that Build Cache Node's secret was regenerated.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/KeySecretPair'
-              example:
-                key: cvzxztkqkqxzc3vcruabpcr264
-                secret: e5ag76yp6abcc5jbxusboca313
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-  /api/build-cache/nodes/{name}/purge:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node. To select the Built-in Build Cache Node, use `Built-in` as name.
-    post:
-      operationId: InitiatePurgeOfBuildCacheNode
-      summary: Deletes all entries from a Build Cache Node.
-      description: |
-        Triggers the deletion of all entries stored at the named Build Cache Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '202':
-          description: Purging the Build Cache Node was successfully initiated.
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NodeNotSignedInError'
-  /api/test-distribution/agent-pools:
-    get:
-      operationId: ListTestDistributionAgentPools
-      summary: Lists Agent Pools
-      description: Returns a list of all Agent Pools.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains a listing of all Agent Pools.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolPage'
-              example:
-                content:
-                  - id: m4yfaq4a
-                    name: abc-agents-pool
-                    minimumSize: 10
-                    maximumSize: 20
-                    capabilities:
-                      - os=linux
-                      - jdk=11
-                      - team-abc
-                    orderIndex: 1
-                  - id: dwc4whvi
-                    name: def-agents-pool
-                    minimumSize: 0
-                    maximumSize: 10
-                    capabilities:
-                      - os=windows
-                      - jdk=11
-                    orderIndex: 2
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    post:
-      operationId: CreateTestDistributionAgentPool
-      summary: Create an Agent Pool
-      description: |
-        Create a new Agent Pool in Gradle Enterprise.
-        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
-        When not specified, the Agent Pool will be added last.
-        When specified, the Agent Pool will be added at the specified index and all other Agent Pools will be moved down.
-        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
-            example:
-              name: abc-agents-pool
-              minimumSize: 10
-              maximumSize: 20
-              capabilities:
-                - os=linux
-                - jdk=11
-                - team-abc
-              orderIndex: 1
-      responses:
-        '200':
-          description: A new Agent Pool was created with the configuration specified in the request.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/agent-pools/{poolId}:
-    parameters:
-      - in: path
-        name: poolId
-        example: m4yfaq4a
-        schema:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        required: true
-        description: The ID of the pool to view.
-    get:
-      operationId: GetTestDistributionAgentPool
-      summary: View the properties of an Agent Pool
-      description: View the identifier, capabilities and size of an Agent Pool.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool whose configuration is described in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    put:
-      operationId: CreateOrUpdateTestDistributionAgentPool
-      summary: Create or update an Agent Pool
-      description: |
-        Create a new Agent Pool in Gradle Enterprise or update the configuration of an existing one.
-        The orderIndex element is optional and can be used to specify the priority order in which the Agent Pool is considered.
-        When not specified, the Agent Pool will be either added last on creation, or will not change position on update.
-        When specified, the Agent Pool will be added at/moved to the specified index and all other Agent Pools will be moved down.
-        If the specified index is out of bounds, the Agent Pool will be added last with the orderIndex adjusted accordingly.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionAgentPoolConfiguration'
-            example:
-              name: abc-agents-pool
-              minimumSize: 10
-              maximumSize: 20
-              capabilities:
-                - os=linux
-                - jdk=11
-                - team-abc
-              orderIndex: 1
-      responses:
-        '200':
-          description: The Agent Pool was created or its configuration was updated successfully.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                capabilities:
-                  - os=linux
-                  - jdk=11
-                  - team-abc
-                orderIndex: 1
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    delete:
-      operationId: DeleteTestDistributionAgentPool
-      summary: Delete an Agent Pool
-      description: View the identifier, capabilities and size of an Agent Pool.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool and it was deleted.
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/agent-pools/{poolId}/status:
-    parameters:
-      - in: path
-        name: poolId
-        example: m4yfaq4a
-        schema:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        required: true
-        description: The ID of the pool to view.
-    get:
-      operationId: GetTestDistributionAgentPoolStatus
-      summary: View the status of an Agent Pool
-      description: |
-        View the status of an Agent Pool, such as its current size.
-        To access this endpoint the user requires the `Test Distribution` permission.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The poolId referenced an existing Agent Pool whose status is described in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionAgentPoolStatus'
-              example:
-                id: m4yfaq4a
-                name: abc-agents-pool
-                minimumSize: 10
-                maximumSize: 20
-                connectedAgents: 15
-                idleAgents: 5
-                desiredAgents: 10
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/api-keys:
-    get:
-      operationId: ListTestDistributionApiKeys
-      summary: Lists Test Distribution API keys
-      description: Returns a list of all Test Distribution API key prefixes.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains a listing of the requested type of (active or revoked) Test Distribution API keys.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefixPage'
-              example:
-                content:
-                  - keyPrefix: am3mbm5kamztbmrmygym5kamct
-                    generatedAt: '2021-01-01T12:59:59Z'
-                    lastUsedAt: '2021-05-03T10:11:02Z'
-                  - keyPrefix: yw3zbwjtnwthbxp3ym6ybxlnew
-                    generatedAt: '2021-04-20T13:21:43Z'
-                    revokedAt: '2022-10-12T11:22:33Z'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    post:
-      operationId: GenerateTestDistributionApiKey
-      summary: Generate a new Test Distribution API key
-      description: Generate a new Test Distribution API key to connect agents and query the agent pool API.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: A new API key was successfully generated and contained in the response.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKey'
-              example:
-                key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/test-distribution/api-keys/{keyPrefix}:
-    parameters:
-      - in: path
-        name: keyPrefix
-        example: riux3fkajs6ivtajxbrunelywk
-        schema:
-          type: string
-          minLength: 26
-          maxLength: 26
-          pattern: ^[a-z2-7]{26}$
-        required: true
-        description: The prefix of the Test Distribution API key.
-    get:
-      operationId: GetTestDistributionApiKey
-      summary: Get a Test Distribution API keyPrefix information.
-      description: Returns information about a Test Distribution API keyPrefix.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The response contains information about the requested Test Distribution API keyPrefix.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-              example:
-                keyPrefix: am3mbm5kamztbmrmygym5kamct
-                generatedAt: '2021-01-01T12:59:59Z'
-                lastUsedAt: '2021-05-03T10:11:02Z'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    put:
-      operationId: InsertTestDistributionApiKey
-      summary: Insert a specific Test Distribution API key
-      description: |
-        Inserts a specific Test Distribution API key to connect agents and query the agent pool API.
-        If a key with the same prefix but different key already exists, it will return 400.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/TestDistributionApiKey'
-            example:
-              key: 46rhyue2hltfwcx36qw7gad74lar4f2clb6a4qo5a433zzx7aqwq
-      responses:
-        '200':
-          description: The API key was successfully inserted.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-              example:
-                keyPrefix: am3mbm5kamztbmrmygym5kamct
-                generatedAt: '2021-01-01T12:59:59Z'
-                lastUsedAt: '2021-05-03T10:11:02Z'
-        '400':
-          $ref: '#/components/responses/BadRequest'
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-    delete:
-      operationId: RevokeTestDistributionApiKey
-      summary: Revoke a Test Distribution API key
-      description: |
-        Revoke the Test Distribution API key for the given prefix which uniquely identifies a Test Distribution API key.
-        A revoked key can no longer be used to connect agents, but it will still be queryable and returned in the list.
-      tags:
-        - TestDistribution
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The API key was revoked successfully.
-        '403':
-          $ref: '#/components/responses/ForbiddenError'
-        '404':
-          $ref: '#/components/responses/UnauthorizedOrNotFoundError'
-  /api/version:
-    get:
-      operationId: GetVersion
-      summary: Provides the version of Gradle Enterprise.
-      description: This endpoint can be accessed by any authenticated user.
-      tags:
-        - Meta
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The version of Gradle Enterprise.
-          content:
-            application/json:
-              schema:
-                title: GradleEnterpriseVersion
-                type: object
-                required:
-                  - string
-                  - year
-                  - release
-                  - patch
-                properties:
-                  string:
-                    type: string
-                    description: The complete version string of format `YEAR.RELEASE.PATCH`, where the patch component is omitted when `0` (e.g. `2022.3`, `2022.3.1`).
-                  year:
-                    type: integer
-                    description: The gregorian calendar year of the release.
-                  release:
-                    type: integer
-                    description: The sequence number of the release for that year, starting with 1.
-                    minimum: 1
-                  patch:
-                    type: integer
-                    description: The patch level of the release, starting with 0.
-                    minimum: 0
-              examples:
-                '2022.3':
-                  value:
-                    string: '2022.3'
-                    year: 2022
-                    release: 3
-                    patch: 0
-                2022.3.1:
-                  value:
-                    string: 2022.3.1
-                    year: 2022
-                    release: 3
-                    patch: 1
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-components:
-  securitySchemes:
-    GradleEnterpriseAccessKey:
-      type: http
-      scheme: bearer
-      bearerFormat: Bearer <<Gradle Enterprise Access Key>>
-      description: |
-        All requests require a Gradle Enterprise access key as a bearer token. 
-        Given an access key of `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required header is `Authorization: Bearer l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
-
-        Please consult the [Gradle Enterprise API User Manual](https://docs.gradle.com/enterprise/api-manual#access_control) for guidance on how to provision access keys and check user permissions.
-  responses:
-    BadRequestError:
-      description: The request cannot be fulfilled due to a problem.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            RequestValidationApiProblemResponse:
-              $ref: '#/components/examples/RequestValidationApiProblemExample'
-    NotFoundError:
-      description: The referenced resource either does not exist or the permissions to know about it are missing.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NotFoundResponse:
-              $ref: '#/components/examples/NotFoundApiProblemExample'
-    UnexpectedError:
-      description: The server encountered an unexpected error.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            UnexpectedErrorResponse:
-              $ref: '#/components/examples/UnexpectedErrorApiProblemExample'
-    NotReadyError:
-      description: The server is not ready to handle the request.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            IngestionNotCompletedResponse:
-              $ref: '#/components/examples/IngestionNotCompletedApiProblemExample'
-    NodeNotSignedInError:
-      description: The node was not signed in with Gradle Enterprise.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NodeNotSignedInResponse:
-              $ref: '#/components/examples/NodeNotSignedInProblemExample'
-    ForbiddenError:
-      description: The authenticated user has insufficient permissions.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            ForbiddenUserResponse:
-              $ref: '#/components/examples/ForbiddenUserExample'
-    UnauthorizedOrNotFoundError:
-      description: No API key was specified in the request, the key has been revoked or the user bearing the key lacks permissions for this operation.
-    BadRequest:
-      description: The request body is malformed or contains invalid values for at least one of the properties.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            CapabilityValidationProblemResponse:
-              $ref: '#/components/examples/CapabilityValidationProblemExample'
-  schemas:
-    ApiProblem:
-      type: object
-      description: |
-        Response detailing why a request was rejected.
-        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807) standard (colloquially known as "Problem JSON") for the response format.
-      required:
-        - type
-        - title
-        - status
-      properties:
-        status:
-          type: integer
-          description: HTTP status code of the problem response.
-        type:
-          type: string
-          description: A URN (Uniform Resource Name) identifying the type of the problem.
-        title:
-          type: string
-          description: The underlying reason for the problem.
-        detail:
-          type: string
-          description: A longer and comprehensive description of the problem. May be `null` if not available.
-          x-nullable: true
-    Build:
-      type: object
-      description: A build with the common attributes of a Build Scan.
-      required:
-        - id
-        - availableAt
-        - buildToolType
-        - buildToolVersion
-        - buildAgentVersion
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        availableAt:
-          type: integer
-          format: int64
-          description: A unix-epoch-time in milliseconds referring to the instant that Gradle Enterprise completed receiving and processing the build.
-        buildToolType:
-          type: string
-          description: The build tool type used to capture the Build Scan.
-        buildToolVersion:
-          type: string
-          description: The build tool version used.
-        buildAgentVersion:
-          type: string
-          description: The build agent version used.
-    Builds:
-      type: array
-      items:
-        $ref: '#/components/schemas/Build'
-      description: List of builds with the common attributes of a Build Scan.
-    BuildQuery:
-      type: object
-      properties:
-        availabilityWaitTimeoutSecs:
-          type: integer
-          minimum: 0
-          description: The time in seconds the server should wait for ingestion before returning a wait timeout response.
-    BuildAttributesValue:
-      type: object
-      description: A Build Scan value.
-      required:
-        - name
-      properties:
-        name:
-          type: string
-          description: The name of the Build Scan value.
-        value:
-          type: string
-          description: The value of the Build Scan value. May be `null` if the Build Scan value is not set.
-    BuildAttributesLink:
-      type: object
-      description: A Build Scan link.
-      required:
-        - label
-        - url
-      properties:
-        label:
-          type: string
-          description: The label of the Build Scan link.
-        url:
-          type: string
-          description: The url  of the Build Scan link.
-    GradleGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: Whether build logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-        taskInputsFileCapturingEnabled:
-          type: boolean
-          description: Whether task input file snapshots capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: Whether test logging output capturing was enabled for the build. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `3.7`. See https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-    GradleBuildOptions:
-      type: object
-      description: Gradle build options for this build.
-      required:
-        - configurationOnDemandEnabled
-        - continuousBuildEnabled
-        - continueOnFailureEnabled
-        - daemonEnabled
-        - dryRunEnabled
-        - maxNumberOfGradleWorkers
-        - offlineModeEnabled
-        - parallelProjectExecutionEnabled
-        - refreshDependenciesEnabled
-        - rerunTasksEnabled
-      properties:
-        buildCacheEnabled:
-          type: boolean
-          description: Whether the build cache was enabled for the build. May be `null` if Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version is < `1.3`. See https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
-          x-nullable: true
-        configurationCacheEnabled:
-          type: boolean
-          description: Whether the configuration cache was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/configuration_cache.html.
-          x-nullable: true
-        configurationOnDemandEnabled:
-          type: boolean
-          description: Whether configuration on demand mode was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
-        continuousBuildEnabled:
-          type: boolean
-          description: Whether continuous build mode was running for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
-        continueOnFailureEnabled:
-          type: boolean
-          description: Whether continue on failure mode was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
-        daemonEnabled:
-          type: boolean
-          description: Whether the build was run with the Gradle Daemon. See https://docs.gradle.org/current/userguide/gradle_daemon.html.
-        dryRunEnabled:
-          type: boolean
-          description: Whether the dry run flag was set for the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
-        fileSystemWatchingEnabled:
-          type: boolean
-          description: Whether file system watching was enabled for the build. May be `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle plugin version is < `3.4`. See https://docs.gradle.org/current/userguide/file_system_watching.html.
-          x-nullable: true
-        maxNumberOfGradleWorkers:
-          type: integer
-          description: The maximum number of build workers used to run the build. See https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
-        offlineModeEnabled:
-          type: boolean
-          description: Whether the offline mode was set for the build. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
-        parallelProjectExecutionEnabled:
-          type: boolean
-          description: Whether parallel project execution was enabled for the build. See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
-        refreshDependenciesEnabled:
-          type: boolean
-          description: Whether the build was set to refresh all dependencies in the dependency cache. See https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
-        rerunTasksEnabled:
-          type: boolean
-          description: Whether the build was forced to run all the tasks, ignoring any up-to-date checks. https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
-    BuildAttributesEnvironment:
-      type: object
-      description: The environment where the build has been executed.
-      required:
-        - operatingSystem
-        - numberOfCpuCores
-        - jreVersion
-        - jvmVersion
-        - jvmMaxMemoryHeapSize
-        - jvmLocale
-      properties:
-        username:
-          type: string
-          description: Operating system username of the build user. May be `null` if no username was captured.
-          x-nullable: true
-        operatingSystem:
-          type: string
-          description: Operating system of the build machine.
-        numberOfCpuCores:
-          type: integer
-          description: Number of cores available to the build JVM.
-        jreVersion:
-          type: string
-          description: Version of the Java runtime that executed the build.
-        jvmVersion:
-          type: string
-          description: Version of the Java Virtual Machine that executed the build.
-        jvmMaxMemoryHeapSize:
-          type: integer
-          format: int64
-          description: Maximum heap memory available to the build JVM in bytes.
-        jvmCharset:
-          type: string
-          description: The default charset of the JVM that executed the build. May be `null` if capturing was not possible.
-          x-nullable: true
-        jvmLocale:
-          type: string
-          description: The locale of the JVM that executed the build.
-        publicHostname:
-          type: string
-          description: The hostname of the build machine, as seen on the network. May be `null` if capturing was not possible.
-          x-nullable: true
-        localHostname:
-          type: string
-          description: The hostname of the build machine, as specified by itself. May be `null` if capturing was not possible.
-          x-nullable: true
-        localIpAddresses:
-          type: array
-          items:
-            type: string
-          description: The local IP addresses of the build machine. May be `null` if capturing was not possible.
-          x-nullable: true
-    GradleAttributes:
-      type: object
-      description: The attributes of a Gradle Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - gradleVersion
-        - pluginVersion
-        - requestedTasks
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        gradleVersion:
-          type: string
-          description: The Gradle version used.
-        pluginVersion:
-          type: string
-          description: The Gradle Enterprise Gradle plugin version used.
-        rootProjectName:
-          type: string
-          description: The root project name. May be `null` in case of very early build failure.
-          x-nullable: true
-        requestedTasks:
-          type: array
-          items:
-            type: string
-          description: The list of requested tasks.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/GradleGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/GradleBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    MavenGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: Whether background Build Scan publication was enabled for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.6`. See https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: Whether to capture build logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-        goalInputsFileCapturingEnabled:
-          type: boolean
-          description: Whether to capture goal input file snapshots for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.1`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: Whether to capture test logging output for the build. May be `null` if Gradle Enterprise Maven extension version is < `1.11`. See https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-    MavenBuildOptions:
-      type: object
-      description: Maven build options for this build.
-      required:
-        - errorsEnabled
-        - maxNumberOfThreads
-        - nonRecursiveEnabled
-        - noSnapshotsUpdatesEnabled
-        - offlineModeEnabled
-        - updateSnapshotsEnabled
-      properties:
-        batchModeEnabled:
-          type: boolean
-          description: Whether the build was configured to run in non-interactive (batch) mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
-          x-nullable: true
-        debugEnabled:
-          type: boolean
-          description: Whether the build was configured to produce execution debug output. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
-          x-nullable: true
-        errorsEnabled:
-          type: boolean
-          description: Whether the build was configured to produce execution error messages. See https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
-        failAtEndEnabled:
-          type: boolean
-          description: Whether the build was configured to only fail at the end. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
-          x-nullable: true
-        failFastEnabled:
-          type: boolean
-          description: Whether the build was configured to fail at the first error. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
-          x-nullable: true
-        failNeverEnabled:
-          type: boolean
-          description: Whether the build was configured to never fail, regardless of errors produced. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
-          x-nullable: true
-        laxChecksumsEnabled:
-          type: boolean
-          description: Whether the build was configured to only warn if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
-          x-nullable: true
-        maxNumberOfThreads:
-          type: integer
-          description: Maximum number of threads used when executing the build. See https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
-        nonRecursiveEnabled:
-          type: boolean
-          description: Whether the build was configured to not recurse into sub-projects. See https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
-        rerunGoals:
-          type: boolean
-          description: Whether the build was configured to rerun goals without checking the build cache. May be `null` if Gradle Enterprise Maven extension version is < `1.13`. See https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
-          x-nullable: true
-        noSnapshotsUpdatesEnabled:
-          type: boolean
-          description: Whether the build was configured to suppress snapshot updates. See https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
-        offlineModeEnabled:
-          type: boolean
-          description: Whether the build was configured to run offline. See https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
-        quietEnabled:
-          type: boolean
-          description: Whether the build was configured to run in quiet mode. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
-          x-nullable: true
-        strictChecksumsEnabled:
-          type: boolean
-          description: Whether the build was configured to fail if checksums don't match. May be `null` if capturing was not possible. See https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
-          x-nullable: true
-        updateSnapshotsEnabled:
-          type: boolean
-          description: Whether the build was configured to force a check for missing releases and updated snapshots on remote repositories. See https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
-    MavenAttributes:
-      type: object
-      description: The attributes of a Maven Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - mavenVersion
-        - extensionVersion
-        - requestedGoals
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        mavenVersion:
-          type: string
-          description: The Maven version used.
-        extensionVersion:
-          type: string
-          description: The Gradle Enterprise Maven extension version used.
-        topLevelProjectName:
-          type: string
-          description: The top level project name. May be `null` in case of very early build failure.
-          x-nullable: true
-        requestedGoals:
-          type: array
-          items:
-            type: string
-          description: The list of requested goals.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/MavenGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/MavenBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    GradleBuildCachePerformanceTaskExecutionEntry:
-      type: object
-      required:
-        - taskPath
-        - taskType
-        - avoidanceOutcome
-        - duration
-      properties:
-        taskPath:
-          type: string
-          description: The full task path.
-        taskType:
-          type: string
-          description: The fully qualified class name of the task.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_up_to_date
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - lifecycle
-            - no-source
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_up_to_date` - Task whose execution was avoided due to build incrementalism
-              * `avoided_from_local_cache` - Task whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Task whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Task which was executed but was cacheable
-              * `executed_not_cacheable` - Task which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Task which was executed and whose cacheability could not be determined
-              * `lifecycle` - Lifecycle task
-              * `no-source` - No-source task
-              * `skipped` - Skipped task
-        duration:
-          type: integer
-          format: int64
-          description: The task duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: The task fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the task was not fingerprinted, or the information was not available.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: The task avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_not_enabled
-            - cache-if_condition_not_matched
-            - disabled_to_ensure_correctness
-            - do-not-cache-if_condition_matched
-            - multiple_outputs_declared
-            - no_outputs_declared
-            - non_cacheable_inputs
-            - non_cacheable_task_action
-            - non_cacheable_task_implementation
-            - non_cacheable_tree_output
-            - overlapping_outputs
-            - task_has_no_actions
-            - task_output_caching_not_enabled
-            - unknown
-          description: |
-            The category of the non-cacheability reason:
-              * `build_cache_not_enabled` - Caching has not been enabled for the build
-              * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
-              * `disabled_to_ensure_correctness` - The task failed validation. Available since Gradle 7.0
-              * `do-not-cache-if_condition_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#doNotCacheIf`
-              * `multiple_outputs_declared` - The task declared multiple outputs
-              * `no_outputs_declared` - The task had no outputs declared
-              * `non_cacheable_inputs` - One of the task inputs was not cacheable, either because some type used as an input to the task was loaded via a custom classloader, or a Java lambda was used as an input. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_action` - One of the task actions was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_implementation` - The task implementation was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_tree_output` - The task had a `org.gradle.api.file.FileTree` or a `org.gradle.api.internal.file.collections.DirectoryFileTree` as an output. Available since Gradle 5.0
-              * `overlapping_outputs` - The tasks outputs overlapped with another task. As Gradle cannot safely determine which task each output file belongs to, it disabled caching            
-              * `task_has_no_actions` - The task did not declare any actions
-              * `task_output_caching_not_enabled` - Caching has not been enabled for the task
-              * `unknown` - Reason for disabled caching was not known
-
-            May be `null` when the task was cacheable or if the information was not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: The human-readable reason for a non-cacheable task. May be `null` when the task was cacheable or if the information was not available.
-          x-nullable: true
-        skipReasonMessage:
-          type: string
-          description: The detailed reason why the task was skipped. May be `null` if the task was not skipped or Gradle versions <7.6 are used.
-          x-nullable: true
-    GradleBuildCachePerformanceTaskExecution:
-      type: array
-      description: A list of executed tasks with performance related information.
-      items:
-        $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
-    GradleBuildCachePerformanceTaskFingerprintingSummary:
-      type: object
-      description: A summary of task fingerprinting. Fingerprinted tasks are part of the `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
-      x-nullable: true
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted tasks.
-        serialDuration:
-          type: integer
-          format: int64
-          description: Sum of all fingerprinting times of fingerprinted tasks in milliseconds.
-    GradleBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - upToDate
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
-        upToDate:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to build incrementalism in milliseconds.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the local build cache in milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the tasks due to their outputs being reused from the remote build cache in milliseconds.
-    GradleBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: Information about the local build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the local build cache was enabled.  May be `null` if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the local cache was disabled due to an error occuring in loading or storing local build cache entries.
-        directory:
-          type: string
-          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: Information about the remote build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        type:
-          type: string
-          description: The type of the connector used to communicate with the remote build cache. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        className:
-          type: string
-          description: The class name of the connector. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: URL of the remote build cache. May be `null` if the remote build cache is disabled or if the given type is not supported or it doesn't have the concept of a URL.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    GradleBuildCachePerformanceBuildCaches:
-      type: object
-      description: Information about the local and remote build caches used in the build. May be `null` if the build cache is globally disabled.
-      x-nullable: true
-      required:
-        - local
-        - remote
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheOverhead'
-    GradleBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Gradle Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveTaskExecutionTime
-        - serialTaskExecutionTime
-        - serializationFactor
-        - taskExecution
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveTaskExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time spent executing tasks in milliseconds. It is the time spent between the start of the first task in the execution phase and the end of the last task of the execution phase, removing any interval where no task is being executed.
-        serialTaskExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time of all task executions in milliseconds. It is the sum of all individual task durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: The ratio of `serialTaskExecutionTime` over the `effectiveTaskExecutionTime`. Quantifies the effect of task parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that tasks were executed faster due to parallelization.
-        taskExecution:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
-        taskFingerprintingSummary:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary'
-        avoidanceSavingsSummary:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary'
-        buildCaches:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
-    MavenBuildCachePerformanceGoalExecutionEntry:
-      type: object
-      required:
-        - goalName
-        - mojoType
-        - goalExecutionId
-        - goalProjectName
-        - avoidanceOutcome
-        - duration
-      properties:
-        goalName:
-          type: string
-          description: The goal name.
-        mojoType:
-          type: string
-          description: The fully qualified class name of the Mojo that provides the implementation of this goal.
-        goalExecutionId:
-          type: string
-          description: The goal execution ID.
-        goalProjectName:
-          type: string
-          description: The goal project name.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_from_local_cache` - Goal whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Goal whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Goal which was executed but was cacheable
-              * `executed_not_cacheable` - Goal which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Goal which was executed and whose cacheability could not be determined
-              * `skipped` - Skipped goal
-        duration:
-          type: integer
-          format: int64
-          description: The goal duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: The goal fingerprinting duration in milliseconds. This duration is part of the complete task execution duration. May be `null` if the goal was not fingerprinted.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: The goal avoidance savings in milliseconds, which can be negative. Negative values indicate that it took more time to reuse outputs than it did to create them originally. May be `null` if the information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_disabled_by_user
-            - goal_execution_marked_non_cacheable
-            - goal_not_supported
-            - no_gradle_enterprise_server_configured
-            - non_clean_build
-            - not_entitled
-            - offline_build
-            - unknown
-            - unknown_entitlements
-          description: |
-            The category of the non-cacheability reason:
-              * `build_cache_disabled_by_user` - The build cache was disabled by the user
-              * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
-              * `goal_not_supported` - The goal did not support build caching
-              * `no_gradle_enterprise_server_configured` - No Gradle Enterprise server was configured
-              * `non_clean_build` - The `clean` lifecycle was not executed 
-              * `not_entitled` - The Gradle Enterprise license entitlements did not allow Maven build caching
-              * `offline_build` - The build was run in offline mode
-              * `unknown` - Reason for disabled caching was not known
-              * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
-
-            May be `null` when the goal execution was cacheable or if the information was not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: The human-readable reason for a non-cacheable goal execution. May be `null` when the goal execution was cacheable or if the information was not available.
-          x-nullable: true
-    MavenBuildCachePerformanceGoalExecution:
-      type: array
-      description: A list of executed goals with performance related information.
-      items:
-        $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
-    MavenBuildCachePerformanceGoalFingerprintingSummary:
-      type: object
-      description: A summary of goal fingerprinting. Fingerprinted goals are part of the `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted goals.
-        serialDuration:
-          type: integer
-          format: int64
-          description: Sum of all fingerprinting times of fingerprinted goals in milliseconds.
-    MavenBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: The ratio of the total avoidance savings against the potential serial execution time (which is the actual serial execution time plus the total avoidance savings). Quantifies the effect of avoidance savings in this build. The bigger the ratio is, the more time was saved when running the build.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the local build cache in milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: The estimated reduction in serial execution time of the goals due to their outputs being reused from the remote build cache in milliseconds.
-    MavenBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: Information about the local build cache used in the build, if it was configured in the build. May be `null` if the local build cache is not configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the local build cache was enabled. May be `null` if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the local cache was disabled due to an error occurring in loading or storing local build cache entries.
-        directory:
-          type: string
-          description: Location of the local build cache. Can be relative or absolute depending on its value. May be `null` if the local build cache is disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: Information about the remote build cache used in the build, if it was configured in the build. May be `null` if the remote build cache is not configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: Whether pushing to the remote build cache was enabled. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: Whether the remote build cache was disabled during the build due to an error occurring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: URL of the remote build cache. May be `null` if the remote build cache is disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    MavenBuildCachePerformanceBuildCaches:
-      type: object
-      description: Information about the local and remote build caches used in the build, if it was configured in the build. May be `null` if the build cache configuration could not be captured (e.g. very early build failure).
-      x-nullable: true
-      required:
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheOverhead'
-    MavenBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Maven Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveProjectExecutionTime
-        - serialProjectExecutionTime
-        - serializationFactor
-        - goalExecution
-        - goalFingerprintingSummary
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveProjectExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time spent executing projects in milliseconds. It is the time spent between the start of the first project execution and the end of the last project execution, removing any interval where no project is being executed.
-        serialProjectExecutionTime:
-          type: integer
-          format: int64
-          description: Wall clock time of all project executions in milliseconds. It is the sum of all individual project durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: The ratio of `serialProjectExecutionTime` over the `effectiveProjectExecutionTime`. Quantifies the effect of project parallelization. A value equal to `1` means that no parallelization occurred. A value greater than `1` means that projects were executed faster due to parallelization.
-        goalExecution:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
-        goalFingerprintingSummary:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary'
-        avoidanceSavingsSummary:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary'
-        buildCaches:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
-    GradleProject:
-      type: object
-      description: A Gradle project.
-      required:
-        - name
-        - path
-      properties:
-        name:
-          type: string
-          description: The name of the project.
-        path:
-          type: string
-          description: The path of the project.
-        parent:
-          type: integer
-          x-nullable: true
-          description: The index of the parent of this Gradle project in the GradleProjects array. May be `null` if this project has no parent (i.e. root project of a build).
-    GradleProjects:
-      type: array
-      items:
-        $ref: '#/components/schemas/GradleProject'
-      description: List of Gradle projects including structural relationships.
-    MavenModule:
-      type: object
-      description: A Maven module.
-      required:
-        - name
-        - groupId
-        - artifactId
-        - version
-      properties:
-        name:
-          type: string
-          description: The name of the module.
-        groupId:
-          type: string
-          description: The group ID of the module.
-        artifactId:
-          type: string
-          description: The artifact ID of the module.
-        version:
-          type: string
-          description: The version of the module.
-        parent:
-          type: integer
-          x-nullable: true
-          description: The index of the parent of this Maven module in the MavenModules array. May be `null` if this module has no parent (i.e. top level project).
-    MavenModules:
-      type: array
-      items:
-        $ref: '#/components/schemas/MavenModule'
-      description: List of Maven modules including structural relationships.
-    ReplicationConfiguration:
-      description: Cached data replication configuration description. May be `null` if replication is not configured.
-      type: object
-      x-nullable: true
-      required:
-        - source
-        - preemptive
-      properties:
-        source:
-          type: string
-          description: The name of the Build Cache Node which is the source of data.
-        preemptive:
-          type: boolean
-          description: Indicates if preemptive replication is enabled from the source.
-    NodeConfiguration:
-      description: A Build Cache Node configuration description.
-      type: object
-      required:
-        - enabled
-      properties:
-        enabled:
-          type: boolean
-          description: Indicates if the Build Cache Node is enabled.
-        replication:
-          $ref: '#/components/schemas/ReplicationConfiguration'
-    KeySecretPair:
-      description: A Build Cache Node key and secret pair.
-      type: object
-      required:
-        - key
-        - secret
-      properties:
-        key:
-          type: string
-          description: A unique identifier for the Build Cache Node in Gradle Enterprise.
-        secret:
-          type: string
-          description: The secret associated with the Build Cache Node.
-    TestDistributionAgentPoolId:
-      description: The unique identifier of the Agent Pool.
-      type: string
-      minLength: 8
-      maxLength: 8
-      pattern: ^[a-z2-7]{8}$
-    TestDistributionAgentPoolConfigurationWithId:
-      description: An Agent Pool configuration.
-      type: object
-      required:
-        - id
-        - name
-        - minimumSize
-        - maximumSize
-        - capabilities
-        - orderIndex
-      properties:
-        id:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-          example: functional-test-agents
-        minimumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        maximumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        orderIndex:
-          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
-          type: integer
-          format: int32
-          minimum: 0
-        capabilities:
-          type: array
-          items:
-            type: string
-            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
-          example:
-            - jdk=17
-            - os=linux
-            - functional-test
-    TestDistributionAgentPoolPage:
-      description: A list of Agent Pools.
-      type: object
-      required:
-        - content
-      properties:
-        content:
-          type: array
-          description: A list of Agent Pool IDs.
-          items:
-            $ref: '#/components/schemas/TestDistributionAgentPoolConfigurationWithId'
-    TestDistributionAgentPoolConfiguration:
-      description: An Agent Pool configuration.
-      type: object
-      required:
-        - name
-        - minimumSize
-        - maximumSize
-        - capabilities
-      properties:
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-          example: functional-test-agents
-        minimumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        maximumSize:
-          type: integer
-          format: int32
-          minimum: 0
-        orderIndex:
-          description: The order in which the Agent Pool is considered for allocation. Lower values are considered first.
-          type: integer
-          format: int32
-          x-nullable: true
-          minimum: 0
-        capabilities:
-          type: array
-          items:
-            type: string
-            pattern: ^([-\w.]+)(?:=([-\w.]+))?$
-          example:
-            - jdk=17
-            - os=linux
-            - functional-test
-    TestDistributionAgentPoolStatus:
-      description: The status of an Agent Pool.
-      type: object
-      required:
-        - id
-        - name
-        - minimumSize
-        - maximumSize
-        - connectedAgents
-        - idleAgents
-        - desiredAgents
-      properties:
-        id:
-          $ref: '#/components/schemas/TestDistributionAgentPoolId'
-        name:
-          type: string
-          description: The alias or display name of the Agent Pool.
-          minLength: 1
-        minimumSize:
-          type: integer
-          format: int32
-        maximumSize:
-          type: integer
-          format: int32
-        connectedAgents:
-          type: integer
-          format: int32
-        idleAgents:
-          type: integer
-          format: int32
-        desiredAgents:
-          type: integer
-          format: int32
-    TestDistributionApiKeyPrefix:
-      description: A Test Distribution Agent API key prefix.
-      type: object
-      required:
-        - keyPrefix
-        - generatedAt
-      properties:
-        keyPrefix:
-          type: string
-          minLength: 26
-          maxLength: 26
-          pattern: ^[a-z2-7]{26}$
-          description: The Agent API key.
-        generatedAt:
-          type: string
-          format: date-time
-        lastUsedAt:
-          type: string
-          format: date-time
-          x-nullable: true
-        revokedAt:
-          type: string
-          format: date-time
-          x-nullable: true
-    TestDistributionApiKeyPrefixPage:
-      description: A list of Test Distribution Agent API key prefixes.
-      type: object
-      required:
-        - content
-      properties:
-        content:
-          type: array
-          items:
-            $ref: '#/components/schemas/TestDistributionApiKeyPrefix'
-    TestDistributionApiKey:
-      description: A Test Distribution Agent API key.
-      type: object
-      required:
-        - key
-      properties:
-        key:
-          type: string
-          minLength: 52
-          maxLength: 52
-          pattern: ^[a-z2-7]{52}$
-          description: The Agent API key.
-  examples:
-    RequestValidationApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:validation
-        title: Request validation failed.
-        detail: |
-          Numeric instance is lower than the required minimum (minimum: 1, found: 0) (Additional info: Query parameter: maxWaitSecs).
-        status: 400
-    NotFoundApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:not-found
-        title: The requested resource is not found or the permissions to know about it are missing.
-        status: 404
-    UnexpectedErrorApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:unexpected-error
-        title: Encountered an internal server error.
-        detail: |
-          The ingestion of build 9r4d13f0r3v3r failed.
-        status: 500
-    IngestionNotCompletedApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-processing-incomplete
-        title: Build processing is incomplete.
-        detail: |
-          The data of build 9r4d13f0r3v3r is not yet available for viewing. Please try again later.
-        status: 503
-    NodeNotSignedInProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:node-not-signed-in
-        title: Node with name not-signed-in-node1 must be signed-in before this operation can be performed.
-        status: 503
-    ForbiddenUserExample:
-      value:
-        type: urn:gradle:enterprise:forbidden
-        title: Insufficient permissions
-        detail: User must have Test Distribution administration permission to access this endpoint.
-        status: 403
-    CapabilityValidationProblemExample:
-      value:
-        type: urn:gradle:enterprise:validation
-        title: Invalid request parameters
-        detail: One or more capabilities have an invalid format.
-        status: 400
-tags:
-  - name: Builds
-    description: |
-      Endpoints related to retrieving details of a Build Scan of the Gradle Enterprise instance. 
-      To access these endpoints the user requires the `Access build data via the API` permission.
-  - name: BuildCache
-    x-displayName: Build Cache
-    description: |
-      Endpoints related to configuring the Build Cache nodes of the Gradle Enterprise instance. 
-      To access these endpoints the user requires the `Configure build caches` permission.
-  - name: Meta
-    x-displayName: Meta
-    description: |
-      Endpoints related to the Gradle Enterprise installation and its state.
-  - name: GradleEnterprise
-    x-traitTag: true
-    description: All endpoints of the Gradle Enterprise API.
-  - name: TestDistribution
-    x-displayName: Test Distribution
-    description: |
-      Endpoints related to the management of Test Distribution resources.
-      To access these endpoints the user requires the `Admin` permission.

From 4ecc2c357498e24b8f7a34fb1b1f070cf29fe892 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:19:39 +0200
Subject: [PATCH 17/57] Remove dead file

---
 .../.openapi-generator-ignore                              | 7 -------
 1 file changed, 7 deletions(-)
 delete mode 100644 components/build-scan-data-loader-online/.openapi-generator-ignore

diff --git a/components/build-scan-data-loader-online/.openapi-generator-ignore b/components/build-scan-data-loader-online/.openapi-generator-ignore
deleted file mode 100644
index d70ed322..00000000
--- a/components/build-scan-data-loader-online/.openapi-generator-ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-build/generated/gradle_enterprise_api/*
-build/generated/gradle_enterprise_api/.github/*
-build/generated/gradle_enterprise_api/api/*
-build/generated/gradle_enterprise_api/docs/*
-build/generated/gradle_enterprise_api/gradle/**/*
-build/generated/gradle_enterprise_api/src/main/AndroidManifest.xml
-build/generated/gradle_enterprise_api/src/test/**/*

From a49947a8e550e994fb37dbf39fc66ab770790ff8 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:26:29 +0200
Subject: [PATCH 18/57] Reduce visibility

---
 .../loader/ReflectiveBuildScanDumpReader.java  | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index 6116b503..d9e3c86e 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -11,7 +11,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 
-public final class ReflectiveBuildScanDumpReader {
+final class ReflectiveBuildScanDumpReader {
 
     private final Object buildScanDumpReader;
 
@@ -19,15 +19,14 @@ private ReflectiveBuildScanDumpReader(Object buildScanDumpReader) {
         this.buildScanDumpReader = buildScanDumpReader;
     }
 
-    @SuppressWarnings("WeakerAccess")
-    public static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
+    static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
         try {
             Class<?> buildScanDumpExtractorClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
             Method newInstance = buildScanDumpExtractorClass.getMethod("newInstance", Path.class);
             Object instance = newInstance.invoke(null, licenseFile);
             return new ReflectiveBuildScanDumpReader(instance);
         } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unable to find the Build Scan dump extractor.", e);
+            throw new IllegalStateException("Unable to find the Build Scan dump extractor", e);
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
@@ -36,26 +35,25 @@ public static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
         }
     }
 
-    @SuppressWarnings({"WeakerAccess", "unused"})
-    public Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
+    Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
         try {
             Method extractGradleBuildScanDump = buildScanDumpReader.getClass().getMethod("readGradleBuildScanDump", Path.class);
             Object gradleBuild = extractGradleBuildScanDump.invoke(buildScanDumpReader, scanDump);
 
             GradleAttributes attributes = (GradleAttributes) gradleBuild.getClass().getField("attributes").get(gradleBuild);
-            GradleBuildCachePerformance  buildCachePerformance = (GradleBuildCachePerformance) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild);
+            GradleBuildCachePerformance buildCachePerformance = (GradleBuildCachePerformance) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild);
 
             return new Pair<>(attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
-        } catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException e) {
+        } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);
         }
     }
 
     @SuppressWarnings({"WeakerAccess", "unused"})
-    public Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path scanDump) {
+    Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path scanDump) {
         try {
             Method extractMavenBuildScanDump = buildScanDumpReader.getClass().getMethod("readMavenBuildScanDump", Path.class);
             Object mavenBuild = extractMavenBuildScanDump.invoke(buildScanDumpReader, scanDump);
@@ -67,7 +65,7 @@ public Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
-        } catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException e) {
+        } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);
         }
     }

From ea83816af59c3ccb535e247ae207a1b829541df3 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:32:13 +0200
Subject: [PATCH 19/57] Introduce API
 BuildScanDataLoader.determineBuildToolType

---
 .../com/gradle/enterprise/loader/BuildScanDataLoader.java    | 4 ++++
 .../gradle/enterprise/loader/OfflineBuildScanDataLoader.java | 5 +++++
 .../gradle/enterprise/loader/OnlineBuildScanDataLoader.java  | 5 +++++
 3 files changed, 14 insertions(+)

diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
index 8d01af52..2732ac03 100644
--- a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -9,10 +9,14 @@
 
 public interface BuildScanDataLoader {
 
+    BuildToolType determineBuildToolType(URI resource);
+
     Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource);
 
     Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource);
 
+    enum BuildToolType {GRADLE, MAVEN}
+
     final class Pair<S, T> {
 
         public final S first;
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index e3edb7a8..eddf2a77 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -21,6 +21,11 @@ public static OfflineBuildScanDataLoader newInstance(Path licenseFile) {
         return new OfflineBuildScanDataLoader(ReflectiveBuildScanDumpReader.newInstance(licenseFile));
     }
 
+    @Override
+    public BuildToolType determineBuildToolType(URI resource) {
+        return BuildToolType.GRADLE;
+    }
+
     @Override
     public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
         return reader.readGradleBuildScanDump(Paths.get(resource));
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 803c13f9..296fa14d 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -9,6 +9,11 @@
 
 public final class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
+    @Override
+    public BuildToolType determineBuildToolType(URI resource) {
+        return BuildToolType.GRADLE;
+    }
+
     @Override
     public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
         return null;

From 5c5bcfd85458da4ff24dfa6186c206d09e082a65 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 17:58:26 +0200
Subject: [PATCH 20/57] Remove repo declaration

---
 components/build-scan-data-loader-offline/build.gradle.kts | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index 969a385a..2f228a7a 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -2,10 +2,6 @@ plugins {
     id("java-library")
 }
 
-repositories {
-    mavenCentral()
-}
-
 dependencies {
     api(project(":build-scan-data-loader-api"))
     "runtimeOnly"(files("build-scan-dump-reader.jar"))

From 8f85cbb23470c30439fc1d89a0d3e57ad7578ec1 Mon Sep 17 00:00:00 2001
From: Sorin Florea <sflorea@gradle.com>
Date: Thu, 11 May 2023 17:58:39 +0200
Subject: [PATCH 21/57] Read build tool type

---
 .../loader/OfflineBuildScanDataLoader.java    |  2 +-
 .../loader/ReflectiveBuildScanDumpReader.java | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index eddf2a77..2a1c5d30 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -23,7 +23,7 @@ public static OfflineBuildScanDataLoader newInstance(Path licenseFile) {
 
     @Override
     public BuildToolType determineBuildToolType(URI resource) {
-        return BuildToolType.GRADLE;
+        return reader.readBuildToolType(Paths.get(resource));
     }
 
     @Override
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index d9e3c86e..251cd4c0 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -11,6 +11,8 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 
+import static com.gradle.enterprise.loader.BuildScanDataLoader.*;
+
 final class ReflectiveBuildScanDumpReader {
 
     private final Object buildScanDumpReader;
@@ -35,6 +37,23 @@ static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
         }
     }
 
+    @SuppressWarnings("WeakerAccess")
+    BuildToolType readBuildToolType(Path scanDump) {
+        try {
+            Class<?> buildToolTypeScanDumpReaderClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
+            Method readBuildToolType = buildToolTypeScanDumpReaderClass.getMethod("readBuildToolType", Path.class);
+            String buildToolType = (String) readBuildToolType.invoke(null, scanDump);
+            return BuildToolType.valueOf(buildToolType);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Unable to find the Build Scan dump extractor.", e);
+        } catch (InvocationTargetException e) {
+            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            throw (RuntimeException) e.getCause();
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new RuntimeException("Unable to read Build Scan dumps: " + e.getMessage(), e);
+        }
+    }
+
     Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
         try {
             Method extractGradleBuildScanDump = buildScanDumpReader.getClass().getMethod("readGradleBuildScanDump", Path.class);

From 761bab93b746c65fdcc7fdde4b2860cbc4e9521f Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Thu, 11 May 2023 18:10:19 +0200
Subject: [PATCH 22/57] Reuse build scan dump reader

---
 .../enterprise/loader/ReflectiveBuildScanDumpReader.java    | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index 251cd4c0..1f468d2b 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -37,15 +37,11 @@ static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
         }
     }
 
-    @SuppressWarnings("WeakerAccess")
     BuildToolType readBuildToolType(Path scanDump) {
         try {
-            Class<?> buildToolTypeScanDumpReaderClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
-            Method readBuildToolType = buildToolTypeScanDumpReaderClass.getMethod("readBuildToolType", Path.class);
+            Method readBuildToolType = buildScanDumpReader.getClass().getMethod("readBuildToolType", Path.class);
             String buildToolType = (String) readBuildToolType.invoke(null, scanDump);
             return BuildToolType.valueOf(buildToolType);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unable to find the Build Scan dump extractor.", e);
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();

From 68ef6d4d51470b30070f75f5dba357a048d474e1 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Thu, 11 May 2023 16:32:46 +0200
Subject: [PATCH 23/57] Extract a Logger interface from ConsoleLogger

This will make it easier to pass Logger instances to the online/offline modules.
---
 .../com/gradle/enterprise/loader/Logger.java  | 19 +++++++++++++++++++
 .../client/AuthenticationConfigurator.java    |  6 +++---
 .../api/client/GradleEnterpriseApiClient.java |  6 +++---
 .../gradle/enterprise/cli/ConsoleLogger.java  | 11 ++++++++++-
 .../cli/FetchBuildScanDataCommand.java        |  3 ++-
 .../network/NetworkSettingsConfigurator.java  |  6 +++---
 6 files changed, 40 insertions(+), 11 deletions(-)
 create mode 100644 components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/Logger.java

diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/Logger.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/Logger.java
new file mode 100644
index 00000000..ebad2bd9
--- /dev/null
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/Logger.java
@@ -0,0 +1,19 @@
+package com.gradle.enterprise.loader;
+
+public interface Logger {
+    void info(String message, Object... args);
+
+    void info(String message);
+
+    void debug(String message);
+
+    void debug(Throwable t);
+
+    void error(String message, Object... args);
+
+    void error(String message);
+
+    void error(Throwable t);
+
+    boolean isDebugEnabled();
+}
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java
index 2ca8eff0..2335017e 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java
@@ -1,7 +1,7 @@
 package com.gradle.enterprise.api.client;
 
 import com.google.common.base.Strings;
-import com.gradle.enterprise.cli.ConsoleLogger;
+import com.gradle.enterprise.loader.Logger;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -23,7 +23,7 @@ public static final class EnvVars {
     private static final String MALFORMED_ENVIRONMENT_VARIABLE_ERROR = "Environment variable " + EnvVars.ACCESS_KEY
             + " is malformed (expected format: 'server-host=access-key' or 'server-host1=access-key1;server-host2=access-key2')";
 
-    public static void configureAuth(URL url, ApiClient client, ConsoleLogger logger) {
+    public static void configureAuth(URL url, ApiClient client, Logger logger) {
         String username = System.getenv(EnvVars.USERNAME);
         String password = System.getenv(EnvVars.PASSWORD);
 
@@ -44,7 +44,7 @@ public static void configureAuth(URL url, ApiClient client, ConsoleLogger logger
         }
     }
 
-    private static Optional<String> lookupAccessKey(URL url, ConsoleLogger logger) {
+    private static Optional<String> lookupAccessKey(URL url, Logger logger) {
         try {
             Properties accessKeysByHost = new Properties();
             accessKeysByHost.putAll(loadMavenHomeAccessKeys());
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index e9e1749f..9083257c 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -9,7 +9,7 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformanceGoalExecutionEntry;
-import com.gradle.enterprise.cli.ConsoleLogger;
+import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
@@ -43,9 +43,9 @@ public class GradleEnterpriseApiClient {
 
     private final CustomValueNames customValueNames;
 
-    private final ConsoleLogger logger;
+    private final Logger logger;
 
-    public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, ConsoleLogger logger) {
+    public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Logger logger) {
         this.baseUrl = baseUrl;
         this.customValueNames = customValueNames;
         this.logger = logger;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/ConsoleLogger.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/ConsoleLogger.java
index 1b340bf6..d367601d 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/ConsoleLogger.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/ConsoleLogger.java
@@ -1,10 +1,11 @@
 package com.gradle.enterprise.cli;
 
+import com.gradle.enterprise.loader.Logger;
 import picocli.CommandLine;
 
 import java.io.PrintStream;
 
-public class ConsoleLogger {
+public class ConsoleLogger implements Logger {
 
     private final PrintStream out;
     private final CommandLine.Help.ColorScheme colorScheme;
@@ -18,15 +19,18 @@ public ConsoleLogger(PrintStream out, CommandLine.Help.ColorScheme colorScheme,
         this.debugEnabled = debugEnabled;
     }
 
+    @Override
     public void info(String message, Object... args) {
         info(String.format(message, args));
     }
 
+    @Override
     public void info(String message) {
         out.println(message);
         lastStatementIncludedNewline = true;
     }
 
+    @Override
     public void debug(String message) {
         if (debugEnabled) {
             out.println(colorScheme.text("@|faint " + message + "|@"));
@@ -34,14 +38,17 @@ public void debug(String message) {
         }
     }
 
+    @Override
     public void debug(Throwable t) {
         debug(colorScheme.stackTraceText(t).plainString());
     }
 
+    @Override
     public void error(String message, Object... args) {
         error(String.format(message, args));
     }
 
+    @Override
     public void error(String message) {
         if (!lastStatementIncludedNewline) {
             out.println();
@@ -50,10 +57,12 @@ public void error(String message) {
         lastStatementIncludedNewline = true;
     }
 
+    @Override
     public void error(Throwable t) {
         error(colorScheme.stackTraceText(t).plainString());
     }
 
+    @Override
     public boolean isDebugEnabled() {
         return debugEnabled;
     }
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index abed1cce..eb5638e8 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -2,6 +2,7 @@
 
 import com.gradle.enterprise.api.client.FailedRequestException;
 import com.gradle.enterprise.api.client.GradleEnterpriseApiClient;
+import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
@@ -27,7 +28,7 @@
 public class FetchBuildScanDataCommand implements Callable<Integer> {
 
     private final CommandLine.Help.ColorScheme colorScheme;
-    private ConsoleLogger logger;
+    private Logger logger;
 
     public FetchBuildScanDataCommand(CommandLine.Help.ColorScheme colorScheme) {
         this.colorScheme = colorScheme;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/network/NetworkSettingsConfigurator.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/network/NetworkSettingsConfigurator.java
index 5a33cca9..cb030163 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/network/NetworkSettingsConfigurator.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/network/NetworkSettingsConfigurator.java
@@ -1,6 +1,6 @@
 package com.gradle.enterprise.network;
 
-import com.gradle.enterprise.cli.ConsoleLogger;
+import com.gradle.enterprise.loader.Logger;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -10,7 +10,7 @@
 
 public class NetworkSettingsConfigurator {
 
-    public static void configureNetworkSettings(Path networkSettingsFile, ConsoleLogger logger) {
+    public static void configureNetworkSettings(Path networkSettingsFile, Logger logger) {
         try {
             configureBasedOnProperties(networkSettingsFile, logger);
         } catch (IOException e) {
@@ -18,7 +18,7 @@ public static void configureNetworkSettings(Path networkSettingsFile, ConsoleLog
         }
     }
 
-    private static void configureBasedOnProperties(Path networkSettingsFile, ConsoleLogger logger) throws IOException {
+    private static void configureBasedOnProperties(Path networkSettingsFile, Logger logger) throws IOException {
         if (Files.isRegularFile(networkSettingsFile)) {
             logger.debug("Loading network settings from " + networkSettingsFile.toAbsolutePath());
             Properties proxyProps = loadProperties(networkSettingsFile);

From a6ce7973b07c9cd4aaa409af763da651b597f4a5 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Thu, 11 May 2023 17:48:30 +0200
Subject: [PATCH 24/57] Implement the online build scan loader

---
 .../build.gradle.kts                          |  10 ++
 .../loader/AuthenticationConfigurator.java    | 122 ++++++++++++++++++
 .../loader/FailedRequestException.java        |  41 ++++++
 .../loader/GradleEnterpriseApiClient.java     | 116 +++++++++++++++++
 .../loader/OnlineBuildScanDataLoader.java     |  80 +++++++++++-
 5 files changed, 366 insertions(+), 3 deletions(-)
 create mode 100644 components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java
 create mode 100644 components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java
 create mode 100644 components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java

diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
index ff225483..b6760dd5 100644
--- a/components/build-scan-data-loader-online/build.gradle.kts
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -2,8 +2,18 @@ plugins {
     id("java-library")
 }
 
+repositories {
+    mavenCentral()
+}
+
 dependencies {
     api(project(":build-scan-data-loader-api"))
+
+    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
+    implementation("com.squareup.okhttp3:okhttp")
+    implementation("com.squareup.okhttp3:okhttp-tls")
+    implementation("com.squareup.okhttp3:logging-interceptor")
+    implementation("com.google.guava:guava:31.1-jre")
 }
 
 java {
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java
new file mode 100644
index 00000000..35845116
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java
@@ -0,0 +1,122 @@
+package com.gradle.enterprise.loader;
+
+import com.google.common.base.Strings;
+import com.gradle.enterprise.api.client.ApiClient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.Properties;
+
+public class AuthenticationConfigurator {
+    public static final class EnvVars {
+        public static final String ACCESS_KEY = "GRADLE_ENTERPRISE_ACCESS_KEY";
+        public static final String USERNAME = "GRADLE_ENTERPRISE_USERNAME";
+        public static final String PASSWORD = "GRADLE_ENTERPRISE_PASSWORD";
+        public static final String GRADLE_USER_HOME = "GRADLE_USER_HOME";
+    }
+
+    private static final String MALFORMED_ENVIRONMENT_VARIABLE_ERROR = "Environment variable " + EnvVars.ACCESS_KEY
+            + " is malformed (expected format: 'server-host=access-key' or 'server-host1=access-key1;server-host2=access-key2')";
+
+    public static void configureAuth(URL url, ApiClient client, Logger logger) {
+        String username = System.getenv(EnvVars.USERNAME);
+        String password = System.getenv(EnvVars.PASSWORD);
+
+        if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) {
+            client.setUsername(username);
+            client.setPassword(password);
+            logger.debug("Using basic authentication.");
+        } else {
+            Optional<String> accessKey = lookupAccessKey(url, logger);
+            accessKey.ifPresent(key -> {
+              client.setBearerToken(key);
+              logger.debug("Using access key authentication.");
+            });
+
+            if (!accessKey.isPresent()) {
+                logger.debug("Using anonymous authentication.");
+            }
+        }
+    }
+
+    private static Optional<String> lookupAccessKey(URL url, Logger logger) {
+        try {
+            Properties accessKeysByHost = new Properties();
+            accessKeysByHost.putAll(loadMavenHomeAccessKeys());
+            accessKeysByHost.putAll(loadGradleHomeAccessKeys());
+            accessKeysByHost.putAll(loadFromEnvVar());
+
+            return Optional.ofNullable(accessKeysByHost.getProperty(url.getHost()));
+        } catch (IOException e) {
+            logger.debug("Error while trying to read access keys: " + e.getMessage() + ". Will try fetching build scan data without authentication.");
+            logger.debug(e);
+            return Optional.empty();
+        }
+    }
+
+    private static Properties loadGradleHomeAccessKeys() throws IOException {
+        Path accessKeysFile = getGradleUserHomeDirectory().resolve("enterprise/keys.properties");
+        return loadAccessKeysFromFile(accessKeysFile);
+    }
+
+    private static Path getGradleUserHomeDirectory() {
+        if (Strings.isNullOrEmpty(System.getenv(EnvVars.GRADLE_USER_HOME))) {
+            return Paths.get(System.getProperty("user.home"), ".gradle");
+        }
+        return Paths.get(System.getenv(EnvVars.GRADLE_USER_HOME));
+    }
+
+    private static Properties loadMavenHomeAccessKeys() throws IOException {
+        Path accessKeysFile = getMavenStorageDirectory().resolve("keys.properties");
+        return loadAccessKeysFromFile(accessKeysFile);
+    }
+
+    private static Path getMavenStorageDirectory() {
+        String defaultLocation = System.getProperty("user.home") + "/.m2/.gradle-enterprise";
+        return Paths.get(System.getProperty("gradle.enterprise.storage.directory", defaultLocation));
+    }
+
+    private static Properties loadAccessKeysFromFile(Path accessKeysFile) throws IOException {
+        Properties accessKeysByHost = new Properties();
+        if (Files.isRegularFile(accessKeysFile)) {
+            try (BufferedReader in = Files.newBufferedReader(accessKeysFile)) {
+                accessKeysByHost.load(in);
+            }
+        }
+        return accessKeysByHost;
+    }
+
+    private static Properties loadFromEnvVar() {
+        Properties accessKeys = new Properties();
+        String value = System.getenv(EnvVars.ACCESS_KEY);
+
+        if(Strings.isNullOrEmpty(value)) {
+            return accessKeys;
+        }
+
+        String[] entries = value.split(";");
+        for(String entry: entries) {
+            if(entry == null) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
+
+            String[] parts = entry.split("=", 2);
+            if (parts.length < 2) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
+
+            String joinedServers = parts[0].trim();
+            String accessKey = parts[1].trim();
+
+            if(joinedServers.isEmpty() || Strings.isNullOrEmpty(accessKey)) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
+            for(String server: joinedServers.split(",")) {
+                server = server.trim();
+                if (server.isEmpty()) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
+                accessKeys.put(server, accessKey);
+            }
+        }
+
+        return accessKeys;
+    }
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java
new file mode 100644
index 00000000..8d1c4bac
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java
@@ -0,0 +1,41 @@
+package com.gradle.enterprise.loader;
+
+import com.gradle.enterprise.api.client.ApiException;
+
+import java.net.URL;
+import java.util.Optional;
+
+public class FailedRequestException extends RuntimeException {
+
+    private final int httpStatusCode;
+
+    private final String responseBody;
+
+    public FailedRequestException(URL buildScanUrl, ApiException e) {
+        super(buildMessage(buildScanUrl, e.getCode()), e);
+        this.httpStatusCode = e.getCode();
+        this.responseBody = e.getResponseBody();
+    }
+
+    public int httpStatusCode() {
+        return httpStatusCode;
+    }
+
+    public Optional<String> getResponseBody() {
+        return Optional.ofNullable(responseBody);
+    }
+
+    private static String buildMessage(URL buildScanUrl, int code) {
+        switch (code) {
+            case 404:
+                return String.format("Build scan %s was not found.%nVerify the build scan exists and you have been " +
+                        "granted the permission 'Access build data via the API'.", buildScanUrl);
+            case 401:
+                return String.format("Failed to authenticate while attempting to fetch build scan %s", buildScanUrl);
+            case 0:
+                return String.format("Unable to connect to server to fetch build scan %s", buildScanUrl);
+            default:
+                return String.format("Encountered an unexpected response while fetching build scan %s", buildScanUrl);
+        }
+    }
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
new file mode 100644
index 00000000..868c90c0
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
@@ -0,0 +1,116 @@
+package com.gradle.enterprise.loader;
+
+import com.gradle.enterprise.api.GradleEnterpriseApi;
+import com.gradle.enterprise.api.client.ApiClient;
+import com.gradle.enterprise.api.client.ApiException;
+import com.gradle.enterprise.api.model.*;
+import com.gradle.enterprise.loader.BuildScanDataLoader.Pair;
+import okhttp3.Credentials;
+import okhttp3.OkHttpClient;
+import okhttp3.tls.HandshakeCertificates;
+
+import java.net.URL;
+import java.time.Duration;
+import java.time.format.DateTimeParseException;
+import java.util.Locale;
+
+public class GradleEnterpriseApiClient {
+
+    private final URL baseUrl;
+    private final GradleEnterpriseApi apiClient;
+
+    public GradleEnterpriseApiClient(URL baseUrl, Logger logger) {
+        this.baseUrl = baseUrl;
+
+        ApiClient client = new ApiClient();
+        client.setHttpClient(configureHttpClient(client.getHttpClient()));
+        client.setBasePath(baseUrl.toString());
+        AuthenticationConfigurator.configureAuth(baseUrl, client, logger);
+
+        this.apiClient = new GradleEnterpriseApi(client);
+    }
+
+    private OkHttpClient configureHttpClient(OkHttpClient httpClient) {
+        OkHttpClient.Builder httpClientBuilder = httpClient.newBuilder();
+
+        configureSsl(httpClientBuilder);
+        configureProxyAuthentication(httpClientBuilder);
+        configureTimeouts(httpClientBuilder);
+
+        return httpClientBuilder.build();
+    }
+
+    private void configureSsl(OkHttpClient.Builder httpClientBuilder) {
+        HandshakeCertificates.Builder trustedCertsBuilder = new HandshakeCertificates.Builder()
+            .addPlatformTrustedCertificates();
+
+        if (allowUntrustedServer()) {
+            trustedCertsBuilder.addInsecureHost(baseUrl.getHost());
+            httpClientBuilder.hostnameVerifier((hostname, session) -> baseUrl.getHost().equals(hostname));
+        }
+
+        HandshakeCertificates trustedCerts = trustedCertsBuilder.build();
+        httpClientBuilder.sslSocketFactory(trustedCerts.sslSocketFactory(), trustedCerts.trustManager());
+    }
+
+    private void configureProxyAuthentication(OkHttpClient.Builder httpClientBuilder) {
+        httpClientBuilder
+            .proxyAuthenticator((route, response) -> {
+                if (response.code() == 407) {
+                    String scheme = response.request().url().scheme().toLowerCase(Locale.ROOT);
+                    String proxyUser = System.getProperty(scheme + ".proxyUser");
+                    String proxyPassword = System.getProperty(scheme + ".proxyPassword");
+                    if (proxyUser != null && proxyPassword != null) {
+                        return response.request().newBuilder()
+                            .header("Proxy-Authorization", Credentials.basic(proxyUser, proxyPassword))
+                            .build();
+                    }
+                }
+                return null;
+            });
+    }
+
+    private boolean allowUntrustedServer() {
+        return Boolean.parseBoolean(System.getProperty("ssl.allowUntrustedServer"));
+    }
+
+    private void configureTimeouts(OkHttpClient.Builder httpClientBuilder) {
+        Duration connectTimeout = parseTimeout("connect.timeout");
+        if (connectTimeout != null) {
+            httpClientBuilder.connectTimeout(connectTimeout);
+        }
+        Duration readTimeout = parseTimeout("read.timeout");
+        if (readTimeout != null) {
+            httpClientBuilder.readTimeout(readTimeout);
+        }
+    }
+
+    private Duration parseTimeout(String key) {
+        String value = System.getProperty(key);
+        try {
+            return value == null ? null : Duration.parse(value);
+        } catch (DateTimeParseException e) {
+            throw new IllegalArgumentException("The value of " + key + " (\"" + value + "\") is not a valid duration.", e);
+        }
+    }
+
+    public String fetchBuildToolType(String buildScanId) throws ApiException {
+        Build build = apiClient.getBuild(buildScanId, null);
+        return build.getBuildToolType();
+    }
+
+    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(String buildScanId) throws ApiException {
+        GradleAttributes attributes = apiClient.getGradleAttributes(buildScanId, null);
+        GradleBuildCachePerformance buildCachePerformance = apiClient.getGradleBuildCachePerformance(buildScanId, null);
+
+        return new Pair<>(attributes, buildCachePerformance);
+    }
+
+    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(String buildScanId) throws ApiException {
+        MavenAttributes attributes = apiClient.getMavenAttributes(buildScanId, null);
+        MavenBuildCachePerformance buildCachePerformance = apiClient.getMavenBuildCachePerformance(buildScanId, null);
+
+        return new Pair<>(attributes, buildCachePerformance);
+    }
+
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 296fa14d..720ab314 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -1,27 +1,101 @@
 package com.gradle.enterprise.loader;
 
+import com.gradle.enterprise.api.client.ApiException;
 import com.gradle.enterprise.api.model.GradleAttributes;
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
+import java.net.MalformedURLException;
 import java.net.URI;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
 
 public final class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
+    // Use a String as the key because using a URL as a map key is dangerous (partly becuase URL is mutable).
+    private final Map<String, GradleEnterpriseApiClient> apiClientsByBaseUrl = new HashMap<>();
+    private final Logger logger;
+
+    public OnlineBuildScanDataLoader(Logger logger) {
+        this.logger = logger;
+    }
+
     @Override
     public BuildToolType determineBuildToolType(URI resource) {
-        return BuildToolType.GRADLE;
+        URL buildScanUrl = toBuildScanURL(resource);
+        GradleEnterpriseApiClient apiClient = getOrCreateClient(buildScanUrl);
+        String buildScanId = extractBuildScanId(buildScanUrl);
+
+        try {
+            return BuildToolType.valueOf(apiClient.fetchBuildToolType(buildScanId).toUpperCase());
+        } catch (ApiException e) {
+            throw new FailedRequestException(buildScanUrl, e);
+        }
     }
 
     @Override
     public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
-        return null;
+        URL buildScanUrl = toBuildScanURL(resource);
+        GradleEnterpriseApiClient apiClient = getOrCreateClient(buildScanUrl);
+        String buildScanId = extractBuildScanId(buildScanUrl);
+
+        try {
+            return apiClient.loadDataForGradle(buildScanId);
+        } catch (ApiException e) {
+            throw new FailedRequestException(buildScanUrl, e);
+        }
     }
 
     @Override
     public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
-        return null;
+        URL buildScanUrl = toBuildScanURL(resource);
+        GradleEnterpriseApiClient apiClient = getOrCreateClient(buildScanUrl);
+        String buildScanId = extractBuildScanId(buildScanUrl);
+
+        try {
+            return apiClient.loadDataForMaven(buildScanId);
+        } catch (ApiException e) {
+            throw new FailedRequestException(buildScanUrl, e);
+        }
+    }
+
+    private synchronized GradleEnterpriseApiClient getOrCreateClient(URL buildScanUrl) {
+        URL baseUrl = extractBaseUrl(buildScanUrl);
+        apiClientsByBaseUrl.computeIfAbsent(buildScanUrl.toString(), k -> new GradleEnterpriseApiClient(baseUrl, logger));
+        return apiClientsByBaseUrl.get(baseUrl.toString());
     }
 
+    private static URL toBuildScanURL(URI resource) {
+        try {
+            return resource.toURL();
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException(resource + " is not a valid Build Scan URL: " + e.getMessage(), e);
+        }
+    }
+
+    //TODO duplicated in NumberedBuildScan
+    private static URL extractBaseUrl(URL buildScanUrl) {
+        String port = (buildScanUrl.getPort() != -1) ? ":" + buildScanUrl.getPort() : "";
+        return toURL(buildScanUrl.getProtocol() + "://" + buildScanUrl.getHost() + port);
+    }
+
+    //TODO duplicated in NumberedBuildScan
+    private static String extractBuildScanId(URL buildScanUrl) {
+        String[] pathSegments = buildScanUrl.getPath().split("/");
+        if (pathSegments.length <= 2 || !pathSegments[1].equals("s")) {
+            throw new IllegalArgumentException("Invalid Build Scan URL: " + buildScanUrl);
+        }
+        return pathSegments[2];
+    }
+
+    //TODO duplicated in NumberedBuildScan
+    private static URL toURL(String url) {
+        try {
+            return new URL(url);
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException("Invalid Build Scan URL: " + url, e);
+        }
+    }
 }

From b2ffd47924ade45ab2a44bb054f38ba7445af9bb Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 06:52:34 +0200
Subject: [PATCH 25/57] Use if/else

---
 .../api/client/GradleEnterpriseApiClient.java | 34 +++++++++----------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 9083257c..a4d3d013 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -130,7 +130,6 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
             if (build.getBuildToolType().equalsIgnoreCase("gradle")) {
                 GradleAttributes attributes = apiClient.getGradleAttributes(buildScanId, null);
                 GradleBuildCachePerformance buildCachePerformance = apiClient.getGradleBuildCachePerformance(buildScanId, null);
-
                 return new BuildScanData(
                     runNum,
                     attributes.getRootProjectName(),
@@ -146,28 +145,27 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
                     buildTimeFrom(buildCachePerformance),
                     serializationFactorFrom(buildCachePerformance)
                 );
-            }
-            if (build.getBuildToolType().equalsIgnoreCase("maven")) {
+            } else if (build.getBuildToolType().equalsIgnoreCase("maven")) {
                 MavenAttributes attributes = apiClient.getMavenAttributes(buildScanId, null);
                 MavenBuildCachePerformance buildCachePerformance = apiClient.getMavenBuildCachePerformance(buildScanId, null);
-
                 return new BuildScanData(
-                    runNum,
-                    attributes.getTopLevelProjectName(),
-                    buildScanId,
-                    baseUrl,
-                    findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
-                    findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
-                    findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
-                    attributes.getRequestedGoals(),
-                    buildOutcomeFrom(attributes),
-                    remoteBuildCacheUrlFrom(buildCachePerformance),
-                    summarizeTaskExecutions(buildCachePerformance),
-                    buildTimeFrom(buildCachePerformance),
-                    serializationFactorFrom(buildCachePerformance)
+                        runNum,
+                        attributes.getTopLevelProjectName(),
+                        buildScanId,
+                        baseUrl,
+                        findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
+                        findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
+                        findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
+                        attributes.getRequestedGoals(),
+                        buildOutcomeFrom(attributes),
+                        remoteBuildCacheUrlFrom(buildCachePerformance),
+                        summarizeTaskExecutions(buildCachePerformance),
+                        buildTimeFrom(buildCachePerformance),
+                        serializationFactorFrom(buildCachePerformance)
                 );
+            } else {
+                throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), build.getBuildToolType()));
             }
-            throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), build.getBuildToolType()));
         } catch (ApiException e) {
             throw new FailedRequestException(buildScan.url(), e);
         }

From 5ed870b50beea9145c16f5791ee685484730bf7e Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:24:54 +0200
Subject: [PATCH 26/57] Add dependencies to online & offline module

---
 components/fetch-build-scan-data-cmdline-tool/build.gradle.kts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
index 581276af..4d87f9fb 100644
--- a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
+++ b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
@@ -16,6 +16,8 @@ repositories {
 
 dependencies {
     implementation(project(":build-scan-data-loader-api"))
+    implementation(project(":build-scan-data-loader-online"))
+    implementation(project(":build-scan-data-loader-offline"))
 
     implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
     implementation("com.squareup.okhttp3:okhttp")

From 40f14d0da6ea71bfd90963526cd55b5f07c6ae78 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:25:36 +0200
Subject: [PATCH 27/57] Add todos

---
 .../gradle/enterprise/loader/BuildScanDataLoader.java  |  1 +
 .../com/gradle/enterprise/model/NumberedBuildScan.java | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
index 2732ac03..2571d7d7 100644
--- a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -11,6 +11,7 @@ public interface BuildScanDataLoader {
 
     BuildToolType determineBuildToolType(URI resource);
 
+    // todo in online mode, fetch the two models in parallel (for both Gradle and Maven)
     Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource);
 
     Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource);
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
index 74b4ac7a..f22026e9 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
@@ -1,6 +1,8 @@
 package com.gradle.enterprise.model;
 
 import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -58,6 +60,14 @@ public URL url() {
         }
     }
 
+    public URI uri() { // todo
+        try {
+            return url().toURI();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static URL extractBaseUrl(URL buildScanUrl) {
         String port = (buildScanUrl.getPort() != -1) ? ":" + buildScanUrl.getPort() : "";
         return toURL(buildScanUrl.getProtocol() + "://" + buildScanUrl.getHost() + port);

From d80ef3364353013e08e506b0561bc77c6319054f Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:29:59 +0200
Subject: [PATCH 28/57] Fix class name references to BuildScanDumpReader

---
 .../loader/ReflectiveBuildScanDumpReader.java        | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index 1f468d2b..3513a09f 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -23,14 +23,14 @@ private ReflectiveBuildScanDumpReader(Object buildScanDumpReader) {
 
     static ReflectiveBuildScanDumpReader newInstance(Path licenseFile) {
         try {
-            Class<?> buildScanDumpExtractorClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
-            Method newInstance = buildScanDumpExtractorClass.getMethod("newInstance", Path.class);
+            Class<?> buildScanDumpReaderClass = Class.forName("com.gradle.enterprise.scans.supporttools.scandump.BuildScanDumpReader");
+            Method newInstance = buildScanDumpReaderClass.getMethod("newInstance", Path.class);
             Object instance = newInstance.invoke(null, licenseFile);
             return new ReflectiveBuildScanDumpReader(instance);
         } catch (ClassNotFoundException e) {
             throw new IllegalStateException("Unable to find the Build Scan dump extractor", e);
         } catch (InvocationTargetException e) {
-            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
         } catch (NoSuchMethodException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dumps: " + e.getMessage(), e);
@@ -43,7 +43,7 @@ BuildToolType readBuildToolType(Path scanDump) {
             String buildToolType = (String) readBuildToolType.invoke(null, scanDump);
             return BuildToolType.valueOf(buildToolType);
         } catch (InvocationTargetException e) {
-            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
         } catch (NoSuchMethodException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dumps: " + e.getMessage(), e);
@@ -60,7 +60,7 @@ Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path
 
             return new Pair<>(attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
-            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
         } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);
@@ -78,7 +78,7 @@ Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path sc
 
             return new Pair<>(attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
-            // We know that the real BuildScanDumpExtractor can only throw runtime exceptions (no checked exceptions are declared)
+            // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
         } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
             throw new RuntimeException("Unable to read Build Scan dump: " + e.getMessage(), e);

From f0fd6b67d7288cab1b7fa423856d156f41f5e3ab Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:34:16 +0200
Subject: [PATCH 29/57] Wire in the BuildScanDumpReader interface

---
 .../api/client/GradleEnterpriseApiClient.java | 103 +++++++++---------
 1 file changed, 53 insertions(+), 50 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index a4d3d013..65f5e8ae 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -1,15 +1,11 @@
 package com.gradle.enterprise.api.client;
 
 import com.gradle.enterprise.api.GradleEnterpriseApi;
-import com.gradle.enterprise.api.model.Build;
-import com.gradle.enterprise.api.model.BuildAttributesValue;
-import com.gradle.enterprise.api.model.GradleAttributes;
-import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
-import com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry;
-import com.gradle.enterprise.api.model.MavenAttributes;
-import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
-import com.gradle.enterprise.api.model.MavenBuildCachePerformanceGoalExecutionEntry;
-import com.gradle.enterprise.loader.Logger;
+import com.gradle.enterprise.api.model.*;
+import com.gradle.enterprise.cli.ConsoleLogger;
+import com.gradle.enterprise.loader.BuildScanDataLoader;
+import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
+import com.gradle.enterprise.loader.OnlineBuildScanDataLoader;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
@@ -24,22 +20,20 @@
 import java.net.URL;
 import java.time.Duration;
 import java.time.format.DateTimeParseException;
-import java.util.AbstractMap;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum.EXECUTED_CACHEABLE;
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum.EXECUTED_NOT_CACHEABLE;
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum.DISABLED_TO_ENSURE_CORRECTNESS;
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum.OVERLAPPING_OUTPUTS;
+import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType;
 
 public class GradleEnterpriseApiClient {
 
     private final URL baseUrl;
     private final GradleEnterpriseApi apiClient;
+    private final BuildScanDataLoader buildScanDataLoader;
 
     private final CustomValueNames customValueNames;
 
@@ -56,6 +50,10 @@ public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames,
         AuthenticationConfigurator.configureAuth(baseUrl, client, logger);
 
         this.apiClient = new GradleEnterpriseApi(client);
+
+        this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
+                ? OfflineBuildScanDataLoader.newInstance(null) // todo
+                : new OnlineBuildScanDataLoader();
     }
 
     private OkHttpClient configureHttpClient(OkHttpClient httpClient) {
@@ -126,28 +124,32 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         int runNum = buildScan.runNum();
         String buildScanId = buildScan.buildScanId();
         try {
-            Build build = apiClient.getBuild(buildScanId, null);
-            if (build.getBuildToolType().equalsIgnoreCase("gradle")) {
-                GradleAttributes attributes = apiClient.getGradleAttributes(buildScanId, null);
-                GradleBuildCachePerformance buildCachePerformance = apiClient.getGradleBuildCachePerformance(buildScanId, null);
+            BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.uri());
+            if (buildToolType.equals(BuildToolType.GRADLE)) {
+                BuildScanDataLoader.Pair<GradleAttributes, GradleBuildCachePerformance> result =
+                        buildScanDataLoader.loadDataForGradle(buildScan.uri());
+                GradleAttributes attributes = result.first;
+                GradleBuildCachePerformance performance = result.second;
                 return new BuildScanData(
-                    runNum,
-                    attributes.getRootProjectName(),
-                    buildScanId,
-                    baseUrl,
-                    findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
-                    findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
-                    findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
-                    attributes.getRequestedTasks(),
-                    buildOutcomeFrom(attributes),
-                    remoteBuildCacheUrlFrom(buildCachePerformance),
-                    summarizeTaskExecutions(buildCachePerformance),
-                    buildTimeFrom(buildCachePerformance),
-                    serializationFactorFrom(buildCachePerformance)
+                        runNum,
+                        attributes.getRootProjectName(),
+                        buildScanId,
+                        baseUrl,
+                        findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
+                        findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
+                        findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
+                        attributes.getRequestedTasks(),
+                        buildOutcomeFrom(attributes),
+                        remoteBuildCacheUrlFrom(performance),
+                        summarizeTaskExecutions(performance),
+                        buildTimeFrom(performance),
+                        serializationFactorFrom(performance)
                 );
-            } else if (build.getBuildToolType().equalsIgnoreCase("maven")) {
-                MavenAttributes attributes = apiClient.getMavenAttributes(buildScanId, null);
-                MavenBuildCachePerformance buildCachePerformance = apiClient.getMavenBuildCachePerformance(buildScanId, null);
+            } else if (buildToolType.equals(BuildToolType.MAVEN)) {
+                BuildScanDataLoader.Pair<MavenAttributes, MavenBuildCachePerformance> result =
+                        buildScanDataLoader.loadDataForMaven(buildScan.uri());
+                MavenAttributes attributes = result.first;
+                MavenBuildCachePerformance performance = result.second;
                 return new BuildScanData(
                         runNum,
                         attributes.getTopLevelProjectName(),
@@ -158,20 +160,20 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
                         findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
                         attributes.getRequestedGoals(),
                         buildOutcomeFrom(attributes),
-                        remoteBuildCacheUrlFrom(buildCachePerformance),
-                        summarizeTaskExecutions(buildCachePerformance),
-                        buildTimeFrom(buildCachePerformance),
-                        serializationFactorFrom(buildCachePerformance)
+                        remoteBuildCacheUrlFrom(performance),
+                        summarizeTaskExecutions(performance),
+                        buildTimeFrom(performance),
+                        serializationFactorFrom(performance)
                 );
             } else {
-                throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), build.getBuildToolType()));
+                throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), buildToolType));
             }
-        } catch (ApiException e) {
-            throw new FailedRequestException(buildScan.url(), e);
+        } catch (RuntimeException e) { // todo fix nesting of exceptions
+            throw e; // throw new FailedRequestException(buildScan.url(), e); // todo fix
         }
     }
 
-    private String findCustomValue(String key, List<BuildAttributesValue> values) {
+    private static String findCustomValue(String key, List<BuildAttributesValue> values) {
         return values.stream()
             .filter(v -> v.getName().equals(key))
             .map(v -> {
@@ -184,21 +186,21 @@ private String findCustomValue(String key, List<BuildAttributesValue> values) {
             .orElse("");
     }
 
-    private String buildOutcomeFrom(GradleAttributes attributes) {
+    private static String buildOutcomeFrom(GradleAttributes attributes) {
         if(!attributes.getHasFailed()) {
             return "SUCCESS";
         }
         return "FAILED";
     }
 
-    private String buildOutcomeFrom(MavenAttributes attributes) {
+    private static String buildOutcomeFrom(MavenAttributes attributes) {
         if(!attributes.getHasFailed()) {
             return "SUCCESS";
         }
         return "FAILED";
     }
 
-    private URL remoteBuildCacheUrlFrom(GradleBuildCachePerformance buildCachePerformance) {
+    private static URL remoteBuildCacheUrlFrom(GradleBuildCachePerformance buildCachePerformance) {
         if (buildCachePerformance.getBuildCaches() == null ||
             buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
             return null;
@@ -212,7 +214,7 @@ private URL remoteBuildCacheUrlFrom(GradleBuildCachePerformance buildCachePerfor
         }
     }
 
-    private URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCachePerformance) {
+    private static URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCachePerformance) {
         if (buildCachePerformance.getBuildCaches() == null ||
             buildCachePerformance.getBuildCaches().getRemote() == null ||
             buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
@@ -228,9 +230,9 @@ private URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCachePerform
     }
 
     @NotNull
-    private Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCachePerformance buildCachePerformance) {
+    private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCachePerformance buildCachePerformance) {
         Map<String, List<GradleBuildCachePerformanceTaskExecutionEntry>> tasksByOutcome = buildCachePerformance.getTaskExecution().stream()
-            .collect(Collectors.groupingBy(this::avoidanceOutcome));
+            .collect(Collectors.groupingBy(GradleEnterpriseApiClient::avoidanceOutcome));
 
         Map<String, TaskExecutionSummary> summariesByOutcome = tasksByOutcome.entrySet()
             .stream()
@@ -243,7 +245,7 @@ private Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCac
         return toTotalAvoidedFromCache(summariesByOutcome);
     }
 
-    private String avoidanceOutcome(GradleBuildCachePerformanceTaskExecutionEntry task) {
+    private static String avoidanceOutcome(GradleBuildCachePerformanceTaskExecutionEntry task) {
         GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum avoidanceOutcome = task.getAvoidanceOutcome();
         GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum nonCacheabilityCategory = task.getNonCacheabilityCategory();
         if (avoidanceOutcome == EXECUTED_NOT_CACHEABLE && (nonCacheabilityCategory == OVERLAPPING_OUTPUTS || nonCacheabilityCategory == DISABLED_TO_ENSURE_CORRECTNESS)) {
@@ -253,7 +255,7 @@ private String avoidanceOutcome(GradleBuildCachePerformanceTaskExecutionEntry ta
     }
 
     @NotNull
-    private Map<String, TaskExecutionSummary> summarizeTaskExecutions(MavenBuildCachePerformance buildCachePerformance) {
+    private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(MavenBuildCachePerformance buildCachePerformance) {
         Map<String, List<MavenBuildCachePerformanceGoalExecutionEntry>> tasksByOutcome = buildCachePerformance.getGoalExecution().stream()
             .collect(Collectors.groupingBy(
                 t -> t.getAvoidanceOutcome().toString()
@@ -330,4 +332,5 @@ private static BigDecimal serializationFactorFrom(GradleBuildCachePerformance bu
     private static BigDecimal serializationFactorFrom(MavenBuildCachePerformance buildCachePerformance) {
         return BigDecimal.valueOf(buildCachePerformance.getSerializationFactor());
     }
+
 }

From 2ad2be384076c005abe72d3cdc7c25e65fa0bf36 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:39:53 +0200
Subject: [PATCH 30/57] Remove GradleEnterpriseApi field

---
 .../enterprise/api/client/GradleEnterpriseApiClient.java  | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 65f5e8ae..755a0689 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -1,6 +1,5 @@
 package com.gradle.enterprise.api.client;
 
-import com.gradle.enterprise.api.GradleEnterpriseApi;
 import com.gradle.enterprise.api.model.*;
 import com.gradle.enterprise.cli.ConsoleLogger;
 import com.gradle.enterprise.loader.BuildScanDataLoader;
@@ -32,10 +31,8 @@
 public class GradleEnterpriseApiClient {
 
     private final URL baseUrl;
-    private final GradleEnterpriseApi apiClient;
-    private final BuildScanDataLoader buildScanDataLoader;
-
     private final CustomValueNames customValueNames;
+    private final BuildScanDataLoader buildScanDataLoader;
 
     private final Logger logger;
 
@@ -44,13 +41,12 @@ public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames,
         this.customValueNames = customValueNames;
         this.logger = logger;
 
+        // todo this all goes away
         ApiClient client = new ApiClient();
         client.setHttpClient(configureHttpClient(client.getHttpClient()));
         client.setBasePath(baseUrl.toString());
         AuthenticationConfigurator.configureAuth(baseUrl, client, logger);
 
-        this.apiClient = new GradleEnterpriseApi(client);
-
         this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
                 ? OfflineBuildScanDataLoader.newInstance(null) // todo
                 : new OnlineBuildScanDataLoader();

From 4235b7667f5a87556e81bf553c3082b1e9c07fcf Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:47:49 +0200
Subject: [PATCH 31/57] Remove logger field

---
 .../enterprise/api/client/GradleEnterpriseApiClient.java   | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 755a0689..5161ac0f 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -1,8 +1,8 @@
 package com.gradle.enterprise.api.client;
 
 import com.gradle.enterprise.api.model.*;
-import com.gradle.enterprise.cli.ConsoleLogger;
 import com.gradle.enterprise.loader.BuildScanDataLoader;
+import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
 import com.gradle.enterprise.loader.OnlineBuildScanDataLoader;
 import com.gradle.enterprise.model.BuildScanData;
@@ -34,12 +34,9 @@ public class GradleEnterpriseApiClient {
     private final CustomValueNames customValueNames;
     private final BuildScanDataLoader buildScanDataLoader;
 
-    private final Logger logger;
-
     public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Logger logger) {
         this.baseUrl = baseUrl;
         this.customValueNames = customValueNames;
-        this.logger = logger;
 
         // todo this all goes away
         ApiClient client = new ApiClient();
@@ -49,7 +46,7 @@ public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames,
 
         this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
                 ? OfflineBuildScanDataLoader.newInstance(null) // todo
-                : new OnlineBuildScanDataLoader();
+                : new OnlineBuildScanDataLoader(logger);
     }
 
     private OkHttpClient configureHttpClient(OkHttpClient httpClient) {

From a50d17a9e4ca9cdd26d82258b19b925c88bf0239 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 07:54:05 +0200
Subject: [PATCH 32/57] Remove api client config code

---
 .../api/client/GradleEnterpriseApiClient.java | 82 ++-----------------
 1 file changed, 5 insertions(+), 77 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 5161ac0f..e81a94ef 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -9,17 +9,16 @@
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
 import com.gradle.enterprise.model.TaskExecutionSummary;
-import okhttp3.Credentials;
-import okhttp3.OkHttpClient;
-import okhttp3.tls.HandshakeCertificates;
 import org.jetbrains.annotations.NotNull;
 
 import java.math.BigDecimal;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.time.Duration;
-import java.time.format.DateTimeParseException;
-import java.util.*;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum.EXECUTED_CACHEABLE;
@@ -28,7 +27,7 @@
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum.OVERLAPPING_OUTPUTS;
 import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType;
 
-public class GradleEnterpriseApiClient {
+public final class GradleEnterpriseApiClient {
 
     private final URL baseUrl;
     private final CustomValueNames customValueNames;
@@ -37,82 +36,11 @@ public class GradleEnterpriseApiClient {
     public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Logger logger) {
         this.baseUrl = baseUrl;
         this.customValueNames = customValueNames;
-
-        // todo this all goes away
-        ApiClient client = new ApiClient();
-        client.setHttpClient(configureHttpClient(client.getHttpClient()));
-        client.setBasePath(baseUrl.toString());
-        AuthenticationConfigurator.configureAuth(baseUrl, client, logger);
-
         this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
                 ? OfflineBuildScanDataLoader.newInstance(null) // todo
                 : new OnlineBuildScanDataLoader(logger);
     }
 
-    private OkHttpClient configureHttpClient(OkHttpClient httpClient) {
-        OkHttpClient.Builder httpClientBuilder = httpClient.newBuilder();
-
-        configureSsl(httpClientBuilder);
-        configureProxyAuthentication(httpClientBuilder);
-        configureTimeouts(httpClientBuilder);
-
-        return httpClientBuilder.build();
-    }
-
-    private void configureSsl(OkHttpClient.Builder httpClientBuilder) {
-        HandshakeCertificates.Builder trustedCertsBuilder = new HandshakeCertificates.Builder()
-            .addPlatformTrustedCertificates();
-
-        if (allowUntrustedServer()) {
-            trustedCertsBuilder.addInsecureHost(baseUrl.getHost());
-            httpClientBuilder.hostnameVerifier((hostname, session) -> baseUrl.getHost().equals(hostname));
-        }
-
-        HandshakeCertificates trustedCerts = trustedCertsBuilder.build();
-        httpClientBuilder.sslSocketFactory(trustedCerts.sslSocketFactory(), trustedCerts.trustManager());
-    }
-
-    private void configureProxyAuthentication(OkHttpClient.Builder httpClientBuilder) {
-        httpClientBuilder
-            .proxyAuthenticator((route, response) -> {
-                if (response.code() == 407) {
-                    String scheme = response.request().url().scheme().toLowerCase(Locale.ROOT);
-                    String proxyUser = System.getProperty(scheme + ".proxyUser");
-                    String proxyPassword = System.getProperty(scheme + ".proxyPassword");
-                    if (proxyUser != null && proxyPassword != null) {
-                        return response.request().newBuilder()
-                            .header("Proxy-Authorization", Credentials.basic(proxyUser, proxyPassword))
-                            .build();
-                    }
-                }
-                return null;
-            });
-    }
-
-    private boolean allowUntrustedServer() {
-        return Boolean.parseBoolean(System.getProperty("ssl.allowUntrustedServer"));
-    }
-
-    private void configureTimeouts(OkHttpClient.Builder httpClientBuilder) {
-        Duration connectTimeout = parseTimeout("connect.timeout");
-        if (connectTimeout != null) {
-            httpClientBuilder.connectTimeout(connectTimeout);
-        }
-        Duration readTimeout = parseTimeout("read.timeout");
-        if (readTimeout != null) {
-            httpClientBuilder.readTimeout(readTimeout);
-        }
-    }
-
-    private Duration parseTimeout(String key) {
-        String value = System.getProperty(key);
-        try {
-            return value == null ? null : Duration.parse(value);
-        } catch (DateTimeParseException e) {
-            throw new IllegalArgumentException("The value of " + key + " (\"" + value + "\") is not a valid duration.", e);
-        }
-    }
-
     public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         int runNum = buildScan.runNum();
         String buildScanId = buildScan.buildScanId();

From 2d121aa14bef6dcfd2a272490f517367d7f9c0c4 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 08:03:07 +0200
Subject: [PATCH 33/57] Extract methods

---
 .../api/client/GradleEnterpriseApiClient.java | 177 +++++++++---------
 1 file changed, 90 insertions(+), 87 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index e81a94ef..8144f80b 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -26,6 +26,7 @@
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum.DISABLED_TO_ENSURE_CORRECTNESS;
 import static com.gradle.enterprise.api.model.GradleBuildCachePerformanceTaskExecutionEntry.NonCacheabilityCategoryEnum.OVERLAPPING_OUTPUTS;
 import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType;
+import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType.*;
 
 public final class GradleEnterpriseApiClient {
 
@@ -44,78 +45,80 @@ public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames,
     public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         int runNum = buildScan.runNum();
         String buildScanId = buildScan.buildScanId();
-        try {
-            BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.uri());
-            if (buildToolType.equals(BuildToolType.GRADLE)) {
-                BuildScanDataLoader.Pair<GradleAttributes, GradleBuildCachePerformance> result =
-                        buildScanDataLoader.loadDataForGradle(buildScan.uri());
-                GradleAttributes attributes = result.first;
-                GradleBuildCachePerformance performance = result.second;
-                return new BuildScanData(
-                        runNum,
-                        attributes.getRootProjectName(),
-                        buildScanId,
-                        baseUrl,
-                        findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
-                        findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
-                        findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
-                        attributes.getRequestedTasks(),
-                        buildOutcomeFrom(attributes),
-                        remoteBuildCacheUrlFrom(performance),
-                        summarizeTaskExecutions(performance),
-                        buildTimeFrom(performance),
-                        serializationFactorFrom(performance)
-                );
-            } else if (buildToolType.equals(BuildToolType.MAVEN)) {
-                BuildScanDataLoader.Pair<MavenAttributes, MavenBuildCachePerformance> result =
-                        buildScanDataLoader.loadDataForMaven(buildScan.uri());
-                MavenAttributes attributes = result.first;
-                MavenBuildCachePerformance performance = result.second;
-                return new BuildScanData(
-                        runNum,
-                        attributes.getTopLevelProjectName(),
-                        buildScanId,
-                        baseUrl,
-                        findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
-                        findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
-                        findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
-                        attributes.getRequestedGoals(),
-                        buildOutcomeFrom(attributes),
-                        remoteBuildCacheUrlFrom(performance),
-                        summarizeTaskExecutions(performance),
-                        buildTimeFrom(performance),
-                        serializationFactorFrom(performance)
-                );
-            } else {
-                throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), buildToolType));
-            }
-        } catch (RuntimeException e) { // todo fix nesting of exceptions
-            throw e; // throw new FailedRequestException(buildScan.url(), e); // todo fix
+        BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.uri());
+        if (buildToolType.equals(GRADLE)) {
+            return analyzeGradleBuild(runNum, buildScanId, buildScanDataLoader.loadDataForGradle(buildScan.uri()));
+        } else if (buildToolType.equals(MAVEN)) {
+            return analyzeMavenBuild(runNum, buildScanId, buildScanDataLoader.loadDataForMaven(buildScan.uri()));
+        } else {
+            throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), buildToolType));
         }
     }
 
+    @NotNull
+    private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<GradleAttributes, GradleBuildCachePerformance> result) {
+        GradleAttributes attributes = result.first;
+        GradleBuildCachePerformance performance = result.second;
+        return new BuildScanData(
+                runNum,
+                attributes.getRootProjectName(),
+                buildScanId,
+                baseUrl,
+                findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
+                findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
+                findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
+                attributes.getRequestedTasks(),
+                buildOutcomeFrom(attributes),
+                remoteBuildCacheUrlFrom(performance),
+                summarizeTaskExecutions(performance),
+                buildTimeFrom(performance),
+                serializationFactorFrom(performance)
+        );
+    }
+
+    @NotNull
+    private BuildScanData analyzeMavenBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<MavenAttributes, MavenBuildCachePerformance> result) {
+        MavenAttributes attributes = result.first;
+        MavenBuildCachePerformance performance = result.second;
+        return new BuildScanData(
+                runNum,
+                attributes.getTopLevelProjectName(),
+                buildScanId,
+                baseUrl,
+                findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
+                findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
+                findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
+                attributes.getRequestedGoals(),
+                buildOutcomeFrom(attributes),
+                remoteBuildCacheUrlFrom(performance),
+                summarizeTaskExecutions(performance),
+                buildTimeFrom(performance),
+                serializationFactorFrom(performance)
+        );
+    }
+
     private static String findCustomValue(String key, List<BuildAttributesValue> values) {
         return values.stream()
-            .filter(v -> v.getName().equals(key))
-            .map(v -> {
-                if (v.getValue() == null) {
-                    return "";
-                }
-                return v.getValue();
-            })
-            .findFirst()
-            .orElse("");
+                .filter(v -> v.getName().equals(key))
+                .map(v -> {
+                    if (v.getValue() == null) {
+                        return "";
+                    }
+                    return v.getValue();
+                })
+                .findFirst()
+                .orElse("");
     }
 
     private static String buildOutcomeFrom(GradleAttributes attributes) {
-        if(!attributes.getHasFailed()) {
+        if (!attributes.getHasFailed()) {
             return "SUCCESS";
         }
         return "FAILED";
     }
 
     private static String buildOutcomeFrom(MavenAttributes attributes) {
-        if(!attributes.getHasFailed()) {
+        if (!attributes.getHasFailed()) {
             return "SUCCESS";
         }
         return "FAILED";
@@ -123,7 +126,7 @@ private static String buildOutcomeFrom(MavenAttributes attributes) {
 
     private static URL remoteBuildCacheUrlFrom(GradleBuildCachePerformance buildCachePerformance) {
         if (buildCachePerformance.getBuildCaches() == null ||
-            buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
+                buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
             return null;
         }
 
@@ -137,8 +140,8 @@ private static URL remoteBuildCacheUrlFrom(GradleBuildCachePerformance buildCach
 
     private static URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCachePerformance) {
         if (buildCachePerformance.getBuildCaches() == null ||
-            buildCachePerformance.getBuildCaches().getRemote() == null ||
-            buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
+                buildCachePerformance.getBuildCaches().getRemote() == null ||
+                buildCachePerformance.getBuildCaches().getRemote().getUrl() == null) {
             return null;
         }
 
@@ -153,15 +156,15 @@ private static URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCache
     @NotNull
     private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCachePerformance buildCachePerformance) {
         Map<String, List<GradleBuildCachePerformanceTaskExecutionEntry>> tasksByOutcome = buildCachePerformance.getTaskExecution().stream()
-            .collect(Collectors.groupingBy(GradleEnterpriseApiClient::avoidanceOutcome));
+                .collect(Collectors.groupingBy(GradleEnterpriseApiClient::avoidanceOutcome));
 
         Map<String, TaskExecutionSummary> summariesByOutcome = tasksByOutcome.entrySet()
-            .stream()
-            .map(GradleEnterpriseApiClient::summarizeForGradle)
-            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+                .stream()
+                .map(GradleEnterpriseApiClient::summarizeForGradle)
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
         Arrays.stream(GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum.values())
-            .forEach(outcome -> summariesByOutcome.putIfAbsent(outcome.toString(), TaskExecutionSummary.ZERO));
+                .forEach(outcome -> summariesByOutcome.putIfAbsent(outcome.toString(), TaskExecutionSummary.ZERO));
 
         return toTotalAvoidedFromCache(summariesByOutcome);
     }
@@ -178,17 +181,17 @@ private static String avoidanceOutcome(GradleBuildCachePerformanceTaskExecutionE
     @NotNull
     private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(MavenBuildCachePerformance buildCachePerformance) {
         Map<String, List<MavenBuildCachePerformanceGoalExecutionEntry>> tasksByOutcome = buildCachePerformance.getGoalExecution().stream()
-            .collect(Collectors.groupingBy(
-                t -> t.getAvoidanceOutcome().toString()
-            ));
+                .collect(Collectors.groupingBy(
+                        t -> t.getAvoidanceOutcome().toString()
+                ));
 
         Map<String, TaskExecutionSummary> summariesByOutcome = tasksByOutcome.entrySet()
-            .stream()
-            .map(GradleEnterpriseApiClient::summarizeForMaven)
-            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+                .stream()
+                .map(GradleEnterpriseApiClient::summarizeForMaven)
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
         Arrays.stream(MavenBuildCachePerformanceGoalExecutionEntry.AvoidanceOutcomeEnum.values())
-            .forEach(outcome -> summariesByOutcome.putIfAbsent(outcome.toString(), TaskExecutionSummary.ZERO));
+                .forEach(outcome -> summariesByOutcome.putIfAbsent(outcome.toString(), TaskExecutionSummary.ZERO));
 
         return toTotalAvoidedFromCache(summariesByOutcome);
     }
@@ -199,13 +202,13 @@ private static Map.Entry<String, TaskExecutionSummary> summarizeForGradle(Map.En
 
     private static TaskExecutionSummary summarizeForGradle(List<GradleBuildCachePerformanceTaskExecutionEntry> tasks) {
         return tasks.stream()
-            .reduce(TaskExecutionSummary.ZERO, (summary, task) ->
-               new TaskExecutionSummary(
-                   summary.totalTasks() + 1,
-                   summary.totalDuration().plus(toDuration(task.getDuration())),
-                   summary.totalAvoidanceSavings().plus(toDuration(task.getAvoidanceSavings()))),
-                TaskExecutionSummary::plus
-            );
+                .reduce(TaskExecutionSummary.ZERO, (summary, task) ->
+                                new TaskExecutionSummary(
+                                        summary.totalTasks() + 1,
+                                        summary.totalDuration().plus(toDuration(task.getDuration())),
+                                        summary.totalAvoidanceSavings().plus(toDuration(task.getAvoidanceSavings()))),
+                        TaskExecutionSummary::plus
+                );
     }
 
     private static Map.Entry<String, TaskExecutionSummary> summarizeForMaven(Map.Entry<String, List<MavenBuildCachePerformanceGoalExecutionEntry>> entry) {
@@ -214,13 +217,13 @@ private static Map.Entry<String, TaskExecutionSummary> summarizeForMaven(Map.Ent
 
     private static TaskExecutionSummary summarizeForMaven(List<MavenBuildCachePerformanceGoalExecutionEntry> tasks) {
         return tasks.stream()
-            .reduce(TaskExecutionSummary.ZERO, (summary, task) ->
-                    new TaskExecutionSummary(
-                        summary.totalTasks() + 1,
-                        summary.totalDuration().plus(toDuration(task.getDuration())),
-                        summary.totalAvoidanceSavings().plus(toDuration(task.getAvoidanceSavings()))),
-                TaskExecutionSummary::plus
-            );
+                .reduce(TaskExecutionSummary.ZERO, (summary, task) ->
+                                new TaskExecutionSummary(
+                                        summary.totalTasks() + 1,
+                                        summary.totalDuration().plus(toDuration(task.getDuration())),
+                                        summary.totalAvoidanceSavings().plus(toDuration(task.getAvoidanceSavings()))),
+                        TaskExecutionSummary::plus
+                );
     }
 
     private static Duration toDuration(Long millis) {

From a9f4f39da9cd8458711fa6af816722fc354443ef Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 08:05:52 +0200
Subject: [PATCH 34/57] Remove dead class

---
 .../client/AuthenticationConfigurator.java    | 122 ------------------
 1 file changed, 122 deletions(-)
 delete mode 100644 components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java
deleted file mode 100644
index 2335017e..00000000
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/AuthenticationConfigurator.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.gradle.enterprise.api.client;
-
-import com.google.common.base.Strings;
-import com.gradle.enterprise.loader.Logger;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Optional;
-import java.util.Properties;
-
-public class AuthenticationConfigurator {
-    public static final class EnvVars {
-        public static final String ACCESS_KEY = "GRADLE_ENTERPRISE_ACCESS_KEY";
-        public static final String USERNAME = "GRADLE_ENTERPRISE_USERNAME";
-        public static final String PASSWORD = "GRADLE_ENTERPRISE_PASSWORD";
-        public static final String GRADLE_USER_HOME = "GRADLE_USER_HOME";
-    }
-
-    private static final String MALFORMED_ENVIRONMENT_VARIABLE_ERROR = "Environment variable " + EnvVars.ACCESS_KEY
-            + " is malformed (expected format: 'server-host=access-key' or 'server-host1=access-key1;server-host2=access-key2')";
-
-    public static void configureAuth(URL url, ApiClient client, Logger logger) {
-        String username = System.getenv(EnvVars.USERNAME);
-        String password = System.getenv(EnvVars.PASSWORD);
-
-        if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) {
-            client.setUsername(username);
-            client.setPassword(password);
-            logger.debug("Using basic authentication.");
-        } else {
-            Optional<String> accessKey = lookupAccessKey(url, logger);
-            accessKey.ifPresent(key -> {
-              client.setBearerToken(key);
-              logger.debug("Using access key authentication.");
-            });
-
-            if (!accessKey.isPresent()) {
-                logger.debug("Using anonymous authentication.");
-            }
-        }
-    }
-
-    private static Optional<String> lookupAccessKey(URL url, Logger logger) {
-        try {
-            Properties accessKeysByHost = new Properties();
-            accessKeysByHost.putAll(loadMavenHomeAccessKeys());
-            accessKeysByHost.putAll(loadGradleHomeAccessKeys());
-            accessKeysByHost.putAll(loadFromEnvVar());
-
-            return Optional.ofNullable(accessKeysByHost.getProperty(url.getHost()));
-        } catch (IOException e) {
-            logger.debug("Error while trying to read access keys: " + e.getMessage() + ". Will try fetching build scan data without authentication.");
-            logger.debug(e);
-            return Optional.empty();
-        }
-    }
-
-    private static Properties loadGradleHomeAccessKeys() throws IOException {
-        Path accessKeysFile = getGradleUserHomeDirectory().resolve("enterprise/keys.properties");
-        return loadAccessKeysFromFile(accessKeysFile);
-    }
-
-    private static Path getGradleUserHomeDirectory() {
-        if (Strings.isNullOrEmpty(System.getenv(EnvVars.GRADLE_USER_HOME))) {
-            return Paths.get(System.getProperty("user.home"), ".gradle");
-        }
-        return Paths.get(System.getenv(EnvVars.GRADLE_USER_HOME));
-    }
-
-    private static Properties loadMavenHomeAccessKeys() throws IOException {
-        Path accessKeysFile = getMavenStorageDirectory().resolve("keys.properties");
-        return loadAccessKeysFromFile(accessKeysFile);
-    }
-
-    private static Path getMavenStorageDirectory() {
-        String defaultLocation = System.getProperty("user.home") + "/.m2/.gradle-enterprise";
-        return Paths.get(System.getProperty("gradle.enterprise.storage.directory", defaultLocation));
-    }
-
-    private static Properties loadAccessKeysFromFile(Path accessKeysFile) throws IOException {
-        Properties accessKeysByHost = new Properties();
-        if (Files.isRegularFile(accessKeysFile)) {
-            try (BufferedReader in = Files.newBufferedReader(accessKeysFile)) {
-                accessKeysByHost.load(in);
-            }
-        }
-        return accessKeysByHost;
-    }
-
-    private static Properties loadFromEnvVar() {
-        Properties accessKeys = new Properties();
-        String value = System.getenv(EnvVars.ACCESS_KEY);
-
-        if(Strings.isNullOrEmpty(value)) {
-            return accessKeys;
-        }
-
-        String[] entries = value.split(";");
-        for(String entry: entries) {
-            if(entry == null) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
-
-            String[] parts = entry.split("=", 2);
-            if (parts.length < 2) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
-
-            String joinedServers = parts[0].trim();
-            String accessKey = parts[1].trim();
-
-            if(joinedServers.isEmpty() || Strings.isNullOrEmpty(accessKey)) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
-            for(String server: joinedServers.split(",")) {
-                server = server.trim();
-                if (server.isEmpty()) throw new RuntimeException(MALFORMED_ENVIRONMENT_VARIABLE_ERROR);
-                accessKeys.put(server, accessKey);
-            }
-        }
-
-        return accessKeys;
-    }
-}

From 751cb3c526b72bc42cb4c892a3a4f6840467eb5c Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 08:11:35 +0200
Subject: [PATCH 35/57] Remove OpenApi references from the cmdline module

---
 .../.openapi-generator-ignore                 |    7 -
 .../api/client/GradleEnterpriseApiClient.java |    5 -
 .../cli/FetchBuildScanDataCommand.java        |    2 -
 .../src/main/openapi/openapi.yaml             | 2059 -----------------
 4 files changed, 2073 deletions(-)
 delete mode 100644 components/fetch-build-scan-data-cmdline-tool/.openapi-generator-ignore
 delete mode 100644 components/fetch-build-scan-data-cmdline-tool/src/main/openapi/openapi.yaml

diff --git a/components/fetch-build-scan-data-cmdline-tool/.openapi-generator-ignore b/components/fetch-build-scan-data-cmdline-tool/.openapi-generator-ignore
deleted file mode 100644
index d70ed322..00000000
--- a/components/fetch-build-scan-data-cmdline-tool/.openapi-generator-ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-build/generated/gradle_enterprise_api/*
-build/generated/gradle_enterprise_api/.github/*
-build/generated/gradle_enterprise_api/api/*
-build/generated/gradle_enterprise_api/docs/*
-build/generated/gradle_enterprise_api/gradle/**/*
-build/generated/gradle_enterprise_api/src/main/AndroidManifest.xml
-build/generated/gradle_enterprise_api/src/test/**/*
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 8144f80b..760a07a5 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -9,7 +9,6 @@
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
 import com.gradle.enterprise.model.TaskExecutionSummary;
-import org.jetbrains.annotations.NotNull;
 
 import java.math.BigDecimal;
 import java.net.MalformedURLException;
@@ -55,7 +54,6 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         }
     }
 
-    @NotNull
     private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<GradleAttributes, GradleBuildCachePerformance> result) {
         GradleAttributes attributes = result.first;
         GradleBuildCachePerformance performance = result.second;
@@ -76,7 +74,6 @@ private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildSc
         );
     }
 
-    @NotNull
     private BuildScanData analyzeMavenBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<MavenAttributes, MavenBuildCachePerformance> result) {
         MavenAttributes attributes = result.first;
         MavenBuildCachePerformance performance = result.second;
@@ -153,7 +150,6 @@ private static URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCache
         }
     }
 
-    @NotNull
     private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCachePerformance buildCachePerformance) {
         Map<String, List<GradleBuildCachePerformanceTaskExecutionEntry>> tasksByOutcome = buildCachePerformance.getTaskExecution().stream()
                 .collect(Collectors.groupingBy(GradleEnterpriseApiClient::avoidanceOutcome));
@@ -178,7 +174,6 @@ private static String avoidanceOutcome(GradleBuildCachePerformanceTaskExecutionE
         return avoidanceOutcome.toString();
     }
 
-    @NotNull
     private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(MavenBuildCachePerformance buildCachePerformance) {
         Map<String, List<MavenBuildCachePerformanceGoalExecutionEntry>> tasksByOutcome = buildCachePerformance.getGoalExecution().stream()
                 .collect(Collectors.groupingBy(
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index eb5638e8..d4980633 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -7,7 +7,6 @@
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
 import com.gradle.enterprise.network.NetworkSettingsConfigurator;
-import org.jetbrains.annotations.NotNull;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 import picocli.CommandLine.Option;
@@ -76,7 +75,6 @@ public Integer call() {
         return ExitCode.OK;
     }
 
-    @NotNull
     private List<BuildScanData> fetchBuildScanData(List<NumberedBuildScan> buildScans, CustomValueNames customValueKeys) {
         return buildScans.stream()
             .parallel()
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/openapi/openapi.yaml b/components/fetch-build-scan-data-cmdline-tool/src/main/openapi/openapi.yaml
deleted file mode 100644
index 0376bafb..00000000
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/openapi/openapi.yaml
+++ /dev/null
@@ -1,2059 +0,0 @@
-openapi: 3.0.3
-info:
-  title: Gradle Enterprise API
-  description: >
-    The Gradle Enterprise API allows programmatic interaction with various
-    aspects of Gradle Enterprise, from configuration to inspecting build data.
-  version: "2022.2.4"
-  license:
-    name: Gradle Enterprise License
-    url: https://gradle.com/legal/gradle-enterprise-software-agreement
-  termsOfService: https://gradle.com/legal/terms-of-service
-  contact:
-    name: Gradle
-    url: https://gradle.com
-  x-logo:
-    url: https://assets.gradle.com/logo/gradle-enterprise-dark-green-primary.svg
-    altText: Gradle Enterprise
-servers:
-  - url: https://ge.mycompany.com
-    description: Your Gradle Enterprise instance.
-security:
-  - GradleEnterpriseAccessKey: []
-paths:
-  /api/builds:
-    description: >
-      Returns a list of builds with basic attributes of a Build Scan. The
-      returned list is capped by the `maxBuilds` and `maxWaitSecs` query
-      parameters. This
-
-      endpoint supports pagination by using the `sinceBuild` query parameter,
-      and the last returned build from a previous call to this endpoint, one can
-      get
-
-      the next batch of builds.
-    parameters:
-      - in: query
-        name: BuildsQuery
-        explode: true
-        schema:
-          title: BuildsQuery
-          type: object
-          properties:
-            since:
-              type: integer
-              format: int64
-              minimum: 0
-              x-nullable: true
-              description: >
-                The time in milliseconds from the Epoch as of when the Build
-                Scan has been received. A value of `0` will process all builds.
-                If not provided, the time
-
-                in milliseconds when the request is received by the Gradle
-                Enterprise instance will be used. This parameter has no effect
-                if `sinceBuild` is used.
-            sinceBuild:
-              type: string
-              x-nullable: true
-              description: >
-                A Build Scan ID allowing to retrieve builds for which Gradle
-                Enterprise completed receiving and processing after the given
-                Build Scan ID (excluding it).
-
-                This parameter has precedence over any value set for the `since`
-                parameter. A valid Build Scan ID must be provided, that is, a
-                Build Scan ID that exists
-
-                in the Gradle Enterprise instance. A Build Scan ID for a deleted
-                build is valid.
-            maxBuilds:
-              type: integer
-              minimum: 0
-              maximum: 1000
-              x-nullable: true
-              description: >
-                The maximum number of builds returned by the query. The query
-                returns when that number is reached or when `maxWaitSecs` is
-                reached.
-
-                If not provided, the default value is `100`.
-            maxWaitSecs:
-              type: integer
-              minimum: 1
-              maximum: 20
-              x-nullable: true
-              description: >
-                The maximum number of seconds to wait for builds before
-                returning. If this time is reached before `maxBuilds` is
-                reached, the query returns with the
-
-                already processed builds. Note that this time is respected with
-                best effort. A query will return soon after this time has passed
-                but there is no 
-
-                guarantee that it exactly returns before this time has passed.
-                If not provided, the default value is `3`.
-    get:
-      operationId: GetBuilds
-      summary: Get a list of builds with basic attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: A list of builds with basic attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Builds'
-              example:
-                - id: 9r4d13f0r3v3r
-                  availableAt: 1635400481000
-                  buildToolType: gradle
-                  buildToolVersion: '7.2'
-                  buildAgentVersion: 3.7.1
-                - id: ji7vz3ey5qdvk
-                  availableAt: 1635400482000
-                  buildToolType: maven
-                  buildToolVersion: 3.8.4
-                  buildAgentVersion: '1.13'
-                - id: cvpd4j7ug7j4q
-                  availableAt: 1635400483000
-                  buildToolType: bazel
-                  buildToolVersion: 6.0.0
-                  buildAgentVersion: '1.0'
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetBuild
-      summary: Get the common attributes of a Build Scan.
-      description: The contained attributes are build tool agnostic.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The common attributes of a Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Build'
-              example:
-                id: 9r4d13f0r3v3r
-                availableAt: 1635400481000
-                buildToolType: gradle
-                buildToolVersion: '7.2'
-                buildAgentVersion: 3.7.1
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleAttributes
-      summary: Get the attributes of a Gradle Build Scan.
-      description: >-
-        This model is Gradle specific and cannot be requested for another build
-        tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleAttributes'
-              example:
-                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:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  taskInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  buildCacheEnabled: true
-                  configurationCacheEnabled: true
-                  configurationOnDemandEnabled: true
-                  continuousBuildEnabled: true
-                  continueOnFailureEnabled: true
-                  daemonEnabled: true
-                  dryRunEnabled: true
-                  fileSystemWatchingEnabled: true
-                  maxNumberOfGradleWorkers: 4
-                  offlineModeEnabled: true
-                  parallelProjectExecutionEnabled: true
-                  refreshDependenciesEnabled: true
-                  rerunTasksEnabled: true
-                environment:
-                  username: gradle
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: gradle
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-attributes:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenAttributes
-      summary: Get the attributes of a Maven Build Scan.
-      description: >-
-        This model is Maven specific and cannot be requested for another build
-        tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The attributes of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenAttributes'
-              example:
-                id: 9r4d13f0r3v3r
-                buildStartTime: 1637316480
-                buildDuration: 11000
-                mavenVersion: 3.8.4
-                extensionVersion: 1.11.1
-                topLevelProjectName: example-project
-                requestedGoals:
-                  - clean
-                  - verify
-                hasFailed: false
-                tags:
-                  - CI
-                  - feature-branch
-                values:
-                  - name: branch
-                    value: feature/one
-                  - name: commitId
-                    value: c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                links:
-                  - label: CI job
-                    url: https://ci.com/job1
-                  - label: GIT commit
-                    url: https://git.com/c874006021712affa4e7bd82d2ec4cd06beaa4f5
-                gradleEnterpriseSettings:
-                  backgroundPublicationEnabled: true
-                  buildOutputCapturingEnabled: true
-                  goalInputsFileCapturingEnabled: true
-                  testOutputCapturingEnabled: true
-                buildOptions:
-                  batchModeEnabled: true
-                  debugEnabled: true
-                  errorsEnabled: true
-                  failAtEndEnabled: true
-                  failFastEnabled: true
-                  failNeverEnabled: true
-                  laxChecksumsEnabled: true
-                  maxNumberOfThreads: 4
-                  nonRecursiveEnabled: true
-                  noSnapshotsUpdatesEnabled: true
-                  offlineModeEnabled: true
-                  quietEnabled: true
-                  rerunGoals: false
-                  strictChecksumsEnabled: true
-                  updateSnapshotsEnabled: true
-                environment:
-                  username: maven
-                  operatingSystem: macOS 12.2.1 (x86_64)
-                  numberOfCpuCores: 16
-                  jreVersion: AdoptOpenJDK OpenJDK Runtime Environment 11.0.11+9
-                  jvmVersion: AdoptOpenJDK OpenJDK 64-Bit Server VM 11.0.11+9 (mixed mode)
-                  jvmMaxMemoryHeapSize: 16777216
-                  jvmCharset: UTF-8
-                  jvmLocale: English (United States)
-                  publicHostname: agent.gradle.com
-                  localHostname: maven
-                  localIpAddresses:
-                    - 192.168.1.126
-                    - 192.168.1.128
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/gradle-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetGradleBuildCachePerformance
-      summary: Get the build cache performance of a Gradle Build Scan.
-      description: >-
-        This model is Gradle specific and cannot be requested for another build
-        tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Gradle Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/GradleBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveTaskExecutionTime: 5000
-                serialTaskExecutionTime: 10000
-                serializationFactor: 2
-                taskExecution:
-                  - taskPath: ':task'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - taskPath: ':task2'
-                    taskType: org.gradle.api.tasks.Task
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                  - taskPath: ':task3'
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    fingerprintingDuration: 6
-                    nonCacheabilityCategory: cache-if_condition_not_matched
-                    nonCacheabilityReason: '''Task outputs cacheable'' not satisfied'
-                taskFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  upToDate: 0
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/builds/{id}/maven-build-cache-performance:
-    parameters:
-      - in: path
-        name: id
-        schema:
-          type: string
-        required: true
-        description: The Build Scan ID.
-      - in: query
-        name: BuildQuery
-        explode: true
-        schema:
-          $ref: '#/components/schemas/BuildQuery'
-    get:
-      operationId: GetMavenBuildCachePerformance
-      summary: Get the build cache performance of a Maven Build Scan.
-      description: >-
-        This model is Maven specific and cannot be requested for another build
-        tool.
-      tags:
-        - Builds
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The build cache performance of a Maven Build Scan.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/MavenBuildCachePerformance'
-              example:
-                id: 9r4d13f0r3v3r
-                buildTime: 5000
-                effectiveProjectExecutionTime: 5000
-                serialProjectExecutionTime: 10000
-                serializationFactor: 2
-                goalExecution:
-                  - goalName: clean:clean
-                    goalExecutionId: default-clean
-                    goalProjectName: myproject
-                    avoidanceOutcome: executed_not_cacheable
-                    duration: 2000
-                    nonCacheabilityCategory: build_cache_disabled_by_user
-                    nonCacheabilityReason: >-
-                      Neither the local or remote build cache were enabled in
-                      the configuration of the build.
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject
-                    avoidanceOutcome: avoided_from_local_cache
-                    duration: 5000
-                    fingerprintingDuration: 5
-                    avoidanceSavings: 6000
-                  - goalName: compiler:compile
-                    mojoType: org.apache.maven.plugin.jar.JarMojo
-                    goalExecutionId: default-compile
-                    goalProjectName: myproject2
-                    avoidanceOutcome: avoided_from_remote_cache
-                    duration: 3000
-                    fingerprintingDuration: 3
-                    avoidanceSavings: 4000
-                goalFingerprintingSummary:
-                  count: 1
-                  serialDuration: 8
-                avoidanceSavingsSummary:
-                  total: 10000
-                  ratio: 0.55556
-                  localBuildCache: 6000
-                  remoteBuildCache: 4000
-                buildCaches:
-                  local:
-                    isEnabled: true
-                    isDisabledDueToError: false
-                  remote:
-                    isEnabled: true
-                    isPushEnabled: true
-                    isDisabledDueToError: false
-                  overhead:
-                    uploading: 100
-                    downloading: 200
-                    packing: 50
-                    unpacking: 25
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NotReadyError'
-  /api/build-cache/nodes/{name}:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: >-
-          The name of the Build Cache Node. To select the Built-in Build Cache
-          Node, use `Built-in` as name.
-    get:
-      operationId: GetBuildCacheNode
-      summary: View the configuration of a Build Cache Node.
-      description: >-
-        View the enablement status and replication configuration of a Build
-        Cache Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: The configuration of a Build Cache Node.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/NodeConfiguration'
-              example:
-                enabled: false
-                replication:
-                  source: parent-node-1
-                  preemptive: true
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-    put:
-      operationId: CreateOrUpdateBuildCacheNode
-      summary: Create or update a Build Cache Node.
-      description: >
-        Create a new Build Cache Node in Gradle Enterprise or update the
-        configuration of an existing one.
-
-        The Built-in Build Cache Node cannot be named as the target of this
-        operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      requestBody:
-        required: true
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/NodeConfiguration'
-            example:
-              enabled: false
-              replication:
-                source: parent-node-1
-                preemptive: true
-      responses:
-        '200':
-          description: >-
-            The name referenced an existing Build Cache Node and that Build
-            Cache Node’s configuration was updated successfully.
-        '201':
-          description: >-
-            A new Build Cache Node was created with the configuration specified
-            in the request.
-        '400':
-          $ref: '#/components/responses/BadRequestError'
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-  /api/build-cache/nodes/{name}/secret:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: The name of the Build Cache Node.
-    post:
-      operationId: RegenerateSecretOfBuildCacheNode
-      summary: Regenerate the secret of a Build Cache Node.
-      description: >
-        Regenerates the secret associated with the named Build Cache Node. The
-        old secret expires immediately, causing the Build Cache Node to
-
-        disconnect from Gradle Enterprise. The Built-in Build Cache Node cannot
-        be named as the target of this operation.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '200':
-          description: >-
-            The name referenced an existing Build Cache Node and that Build
-            Cache Node's secret was regenerated.
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/KeySecretPair'
-              example:
-                key: cvzxztkqkqxzc3vcruabpcr264
-                secret: e5ag76yp6abcc5jbxusboca313
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-  /api/build-cache/nodes/{name}/purge:
-    parameters:
-      - in: path
-        name: name
-        schema:
-          type: string
-        required: true
-        description: >-
-          The name of the Build Cache Node. To select the Built-in Build Cache
-          Node, use `Built-in` as name.
-    post:
-      operationId: InitiatePurgeOfBuildCacheNode
-      summary: Deletes all entries from a Build Cache Node.
-      description: >
-        Triggers the deletion of all entries stored at the named Build Cache
-        Node.
-      tags:
-        - BuildCache
-        - GradleEnterprise
-      responses:
-        '202':
-          description: Purging the Build Cache Node was successfully initiated.
-        '404':
-          $ref: '#/components/responses/NotFoundError'
-        '500':
-          $ref: '#/components/responses/UnexpectedError'
-        '503':
-          $ref: '#/components/responses/NodeNotSignedInError'
-components:
-  securitySchemes:
-    GradleEnterpriseAccessKey:
-      type: http
-      in: header
-      scheme: bearer
-      bearerFormat: Bearer <<Gradle Enterprise Access Key>>
-      description: >
-        All requests require a Gradle Enterprise access key as a bearer token. 
-
-        Given an access key of
-        `l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`, the required
-        header is `Authorization: Bearer
-        l3an7wk3j4ze5v4mi7rvgjf2p7g44nvlswg4cpvdonjs7rzd4kmq`.
-
-
-        Please consult the [Gradle Enterprise API User
-        Manual](https://docs.gradle.com/api-manual#access_control) for guidance
-        on how to provision access keys and check user permissions.
-  responses:
-    BadRequestError:
-      description: The request cannot be fulfilled due to a problem.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            BuildDeletedProblemResponse:
-              $ref: '#/components/examples/BuildDeletedApiProblemExample'
-            NonApplicableModelProblemResponse:
-              $ref: '#/components/examples/NonApplicableModelApiProblemExample'
-            RequestValidationApiProblemResponse:
-              $ref: '#/components/examples/RequestValidationApiProblemExample'
-    NotFoundError:
-      description: >-
-        The referenced resource either does not exist or the permissions to know
-        about it are missing.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NotFoundResponse:
-              $ref: '#/components/examples/NotFoundApiProblemExample'
-    UnexpectedError:
-      description: The server encountered an unexpected error.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            UnexpectedErrorResponse:
-              $ref: '#/components/examples/UnexpectedErrorApiProblemExample'
-    NotReadyError:
-      description: The server is not ready to handle the request.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            IngestionNotCompletedResponse:
-              $ref: '#/components/examples/IngestionNotCompletedApiProblemExample'
-    NodeNotSignedInError:
-      description: The node was not signed in with Gradle Enterprise.
-      content:
-        application/problem+json:
-          schema:
-            $ref: '#/components/schemas/ApiProblem'
-          examples:
-            NodeNotSignedInResponse:
-              $ref: '#/components/examples/NodeNotSignedInProblemExample'
-  schemas:
-    ApiProblem:
-      type: object
-      description: >
-        Response detailing why a request was rejected.
-
-        Adheres to the [RFC-7807](https://datatracker.ietf.org/doc/html/rfc7807)
-        standard (colloquially known as "Problem JSON") for the response format.
-      required:
-        - type
-        - title
-        - status
-      properties:
-        status:
-          type: integer
-          description: HTTP status code of the problem response.
-        type:
-          type: string
-          description: A URN (Uniform Resource Name) identifying the type of the problem.
-        title:
-          type: string
-          description: The underlying reason for the problem.
-        detail:
-          type: string
-          description: >-
-            A longer and comprehensive description of the problem. May be `null`
-            if not available.
-          x-nullable: true
-    Build:
-      type: object
-      description: A build with basic attributes of a Build Scan.
-      required:
-        - id
-        - availableAt
-        - buildToolType
-        - buildToolVersion
-        - buildAgentVersion
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        availableAt:
-          type: integer
-          format: int64
-          description: >-
-            The time in milliseconds from the Epoch as of when the Build Scan
-            has been received.
-        buildToolType:
-          type: string
-          description: The build tool type used to caputre the Build Scan.
-        buildToolVersion:
-          type: string
-          description: The build tool version used.
-        buildAgentVersion:
-          type: string
-          description: The build agent version used.
-    Builds:
-      type: array
-      items:
-        $ref: '#/components/schemas/Build'
-      description: List of builds with basic attributes of a Build Scan.
-    BuildQuery:
-      type: object
-      properties:
-        availabilityWaitTimeoutSecs:
-          type: integer
-          minimum: 0
-          description: >-
-            The time in seconds the server should wait for ingestion before
-            returning a wait timeout response.
-    BuildAttributesValue:
-      type: object
-      description: A Build Scan value.
-      required:
-        - name
-      properties:
-        name:
-          type: string
-          description: The name of the Build Scan value.
-        value:
-          type: string
-          description: >-
-            The value of the Build Scan value. May be `null` if the Build Scan
-            value is not set.
-    BuildAttributesLink:
-      type: object
-      description: A Build Scan link.
-      required:
-        - label
-        - url
-      properties:
-        label:
-          type: string
-          description: The label of the Build Scan link.
-        url:
-          type: string
-          description: The url  of the Build Scan link.
-    GradleGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: >-
-            Whether background Build Scan publication was enabled for the build.
-            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
-            Gradle plugin version is < `3.4`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether build logging output capturing was enabled for the build.
-            May be `null` if Gradle version is < `5.0` or Gradle Enterprise
-            Gradle plugin version is < `3.7`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-        taskInputsFileCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether task input file snapshots capturing was enabled for the
-            build. May be `null` if Gradle version is < `5.0` or Gradle
-            Enterprise Gradle plugin version is < `2.1`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_task_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether test logging output capturing was enabled for the build. May
-            be `null` if Gradle version is < `5.0` or Gradle Enterprise Gradle
-            plugin version is < `3.7`. See
-            https://docs.gradle.com/enterprise/gradle-plugin/#capturing_build_and_test_outputs.
-          x-nullable: true
-    GradleBuildOptions:
-      type: object
-      description: Gradle build options for this build.
-      required:
-        - configurationOnDemandEnabled
-        - continuousBuildEnabled
-        - continueOnFailureEnabled
-        - daemonEnabled
-        - dryRunEnabled
-        - maxNumberOfGradleWorkers
-        - offlineModeEnabled
-        - parallelProjectExecutionEnabled
-        - refreshDependenciesEnabled
-        - rerunTasksEnabled
-      properties:
-        buildCacheEnabled:
-          type: boolean
-          description: >-
-            Whether the build cache was enabled for the build. May be `null` if
-            Gradle version is < `3.1` or Gradle Enterprise Gradle plugin version
-            is < `1.3`. See
-            https://docs.gradle.org/current/javadoc/org/gradle/StartParameter.html#isBuildCacheEnabled--.
-          x-nullable: true
-        configurationCacheEnabled:
-          type: boolean
-          description: >-
-            Whether the configuration cache was enabled for the build. May be
-            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
-            plugin version is < `3.4`. See
-            https://docs.gradle.org/current/userguide/configuration_cache.html.
-          x-nullable: true
-        configurationOnDemandEnabled:
-          type: boolean
-          description: >-
-            Whether configuration on demand mode was enabled for the build. See
-            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand.
-        continuousBuildEnabled:
-          type: boolean
-          description: >-
-            Whether continuous build mode was running for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build.
-        continueOnFailureEnabled:
-          type: boolean
-          description: >-
-            Whether continue on failure mode was set for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure.
-        daemonEnabled:
-          type: boolean
-          description: >-
-            Whether the build was run with the Gradle Daemon. See
-            https://docs.gradle.org/current/userguide/gradle_daemon.html.
-        dryRunEnabled:
-          type: boolean
-          description: >-
-            Whether the dry run flag was set for the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options.
-        fileSystemWatchingEnabled:
-          type: boolean
-          description: >-
-            Whether file system watching was enabled for the build. May be
-            `null` if Gradle version is < `6.6` or Gradle Enterprise Gradle
-            plugin version is < `3.4`. See
-            https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:daemon_watch_fs.
-          x-nullable: true
-        maxNumberOfGradleWorkers:
-          type: integer
-          description: >-
-            The maximum number of build workers used to run the build. See
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_performance.
-        offlineModeEnabled:
-          type: boolean
-          description: >-
-            Whether the offline mode was set for the build. See
-            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:offline-mode.
-        parallelProjectExecutionEnabled:
-          type: boolean
-          description: >-
-            Whether parallel project execution was enabled for the build. See
-            https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:parallel_execution.
-        refreshDependenciesEnabled:
-          type: boolean
-          description: >-
-            Whether the build was set to refresh all dependencies in the
-            dependency cache. See
-            https://docs.gradle.org/current/userguide/dynamic_versions.html#sec:refreshing-dependencies.
-        rerunTasksEnabled:
-          type: boolean
-          description: >-
-            Whether the build was forced to run all the tasks, ignoring any
-            up-to-date checks.
-            https://docs.gradle.org/current/userguide/command_line_interface.html#sec:rerun_tasks.
-    BuildAttributesEnvironment:
-      type: object
-      description: The environment where the build has been executed.
-      required:
-        - operatingSystem
-        - numberOfCpuCores
-        - jreVersion
-        - jvmVersion
-        - jvmMaxMemoryHeapSize
-        - jvmLocale
-      properties:
-        username:
-          type: string
-          description: >-
-            Operating system username of the build user. May be `null` if no
-            username was captured.
-          x-nullable: true
-        operatingSystem:
-          type: string
-          description: Operating system of the build machine.
-        numberOfCpuCores:
-          type: integer
-          description: Number of cores available to the build JVM.
-        jreVersion:
-          type: string
-          description: Version of the Java runtime that executed the build.
-        jvmVersion:
-          type: string
-          description: Version of the Java Virtual Machine that executed the build.
-        jvmMaxMemoryHeapSize:
-          type: integer
-          format: int64
-          description: Maximum heap memory available to the build JVM in bytes.
-        jvmCharset:
-          type: string
-          description: >-
-            The default charset of the JVM that executed the build. May be
-            `null` if capturing was not possible.
-          x-nullable: true
-        jvmLocale:
-          type: string
-          description: The locale of the JVM that executed the build.
-        publicHostname:
-          type: string
-          description: >-
-            The hostname of the build machine, as seen on the network. May be
-            `null` if capturing was not possible.
-          x-nullable: true
-        localHostname:
-          type: string
-          description: >-
-            The hostname of the build machine, as specified by itself. May be
-            `null` if capturing was not possible.
-          x-nullable: true
-        localIpAddresses:
-          type: array
-          items:
-            type: string
-          description: >-
-            The local IP addresses of the build machine. May be `null` if
-            capturing was not possible.
-          x-nullable: true
-    GradleAttributes:
-      type: object
-      description: The attributes of a Gradle Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - gradleVersion
-        - pluginVersion
-        - requestedTasks
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        gradleVersion:
-          type: string
-          description: The Gradle version used.
-        pluginVersion:
-          type: string
-          description: The Gradle Enterprise Gradle plugin version used.
-        rootProjectName:
-          type: string
-          description: >-
-            The root project name. May be `null` in case of very early build
-            failure.
-          x-nullable: true
-        requestedTasks:
-          type: array
-          items:
-            type: string
-          description: The list of requested tasks.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/GradleGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/GradleBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    MavenGradleEnterpriseSettings:
-      type: object
-      description: Settings for Gradle Enterprise.
-      properties:
-        backgroundPublicationEnabled:
-          type: boolean
-          description: >-
-            Whether background Build Scan publication was enabled for the build.
-            May be `null` if Gradle Enterprise Maven extension version is <
-            `1.6`. See
-            https://docs.gradle.com/enterprise/maven-extension/#configuring_background_uploading.
-          x-nullable: true
-        buildOutputCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether to capture build logging output for the build. May be `null`
-            if Gradle Enterprise Maven extension version is < `1.11`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-        goalInputsFileCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether to capture goal input file snapshots for the build. May be
-            `null` if Gradle Enterprise Maven extension version is < `1.1`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_goal_input_files.
-          x-nullable: true
-        testOutputCapturingEnabled:
-          type: boolean
-          description: >-
-            Whether to capture test logging output for the build. May be `null`
-            if Gradle Enterprise Maven extension version is < `1.11`. See
-            https://docs.gradle.com/enterprise/maven-extension/#capturing_build_and_test_outputs.
-          x-nullable: true
-    MavenBuildOptions:
-      type: object
-      description: Maven build options for this build.
-      required:
-        - errorsEnabled
-        - maxNumberOfThreads
-        - nonRecursiveEnabled
-        - noSnapshotsUpdatesEnabled
-        - offlineModeEnabled
-        - updateSnapshotsEnabled
-      properties:
-        batchModeEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to run in non-interactive (batch)
-            mode. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#batch-mode.
-          x-nullable: true
-        debugEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to produce execution debug output.
-            May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#debug.
-          x-nullable: true
-        errorsEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to produce execution error
-            messages. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#errors.
-        failAtEndEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to only fail at the end. May be
-            `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-at-end.
-          x-nullable: true
-        failFastEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to fail at the first error. May be
-            `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-fast.
-          x-nullable: true
-        failNeverEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to never fail, regardless of errors
-            produced. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#fail-never.
-          x-nullable: true
-        laxChecksumsEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to only warn if checksums don't
-            match. May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#lax-checksums.
-          x-nullable: true
-        maxNumberOfThreads:
-          type: integer
-          description: >-
-            Maximum number of threads used when executing the build. See
-            https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3.
-        nonRecursiveEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to not recurse into sub-projects.
-            See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#non-recursive.
-        rerunGoals:
-          type: boolean
-          description: >-
-            Whether the build was configured to rerun goals without checking the
-            build cache. May be `null` if Gradle Enterprise Maven extension
-            version is < `1.13`. See
-            https://docs.gradle.com/enterprise/maven-extension/#rerunning_goals.
-          x-nullable: true
-        noSnapshotsUpdatesEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to suppress snapshot updates. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#no-snapshot-updates.
-        offlineModeEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to run offline. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#offline.
-        quietEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to run in quiet mode. May be `null`
-            if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#quiet.
-          x-nullable: true
-        strictChecksumsEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to fail if checksums don't match.
-            May be `null` if capturing was not possible. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#strict-checksums.
-          x-nullable: true
-        updateSnapshotsEnabled:
-          type: boolean
-          description: >-
-            Whether the build was configured to force a check for missing
-            releases and updated snapshots on remote repositories. See
-            https://maven.apache.org/ref/current/maven-embedder/cli.html#update-snapshots.
-    MavenAttributes:
-      type: object
-      description: The attributes of a Maven Build Scan.
-      required:
-        - id
-        - buildStartTime
-        - buildDuration
-        - mavenVersion
-        - extensionVersion
-        - requestedGoals
-        - hasFailed
-        - tags
-        - values
-        - links
-        - gradleEnterpriseSettings
-        - buildOptions
-        - environment
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildStartTime:
-          type: integer
-          format: int64
-          description: The time when the build started, as milliseconds since Epoch.
-        buildDuration:
-          type: integer
-          format: int64
-          description: The duration of the build, as milliseconds since Epoch.
-        mavenVersion:
-          type: string
-          description: The Maven version used.
-        extensionVersion:
-          type: string
-          description: The Gradle Enterprise Maven extension version used.
-        topLevelProjectName:
-          type: string
-          description: >-
-            The top level project name. May be `null` in case of very early
-            build failure.
-          x-nullable: true
-        requestedGoals:
-          type: array
-          items:
-            type: string
-          description: The list of requested goals.
-        hasFailed:
-          type: boolean
-          description: True when the build failed, false otherwise.
-        tags:
-          type: array
-          items:
-            type: string
-          description: The list of Build Scan tags.
-        values:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesValue'
-          description: The list of Build Scan values.
-        links:
-          type: array
-          items:
-            $ref: '#/components/schemas/BuildAttributesLink'
-          description: The list of Build Scan links.
-        gradleEnterpriseSettings:
-          $ref: '#/components/schemas/MavenGradleEnterpriseSettings'
-        buildOptions:
-          $ref: '#/components/schemas/MavenBuildOptions'
-        environment:
-          $ref: '#/components/schemas/BuildAttributesEnvironment'
-    GradleBuildCachePerformanceTaskExecutionEntry:
-      type: object
-      required:
-        - taskPath
-        - avoidanceOutcome
-        - duration
-      properties:
-        taskPath:
-          type: string
-          description: The full task path.
-        taskType:
-          type: string
-          description: The fully qualified class name of the task.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_up_to_date
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - lifecycle
-            - no-source
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_up_to_date` - Task whose execution was avoided due to build incrementalism
-              * `avoided_from_local_cache` - Task whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Task whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Task which was executed but was cacheable
-              * `executed_not_cacheable` - Task which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Task which was executed and whose cacheability could not be determined
-              * `lifecycle` - Lifecycle task
-              * `no-source` - No-source task
-              * `skipped` - Skipped task
-        duration:
-          type: integer
-          format: int64
-          description: The task duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: >-
-            The task fingerprinting duration in milliseconds. This duration is
-            part of the complete task execution duration. May be `null` if the
-            task was not fingerprinted, or the information was not available.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: >-
-            The task avoidance savings in milliseconds, which can be negative.
-            Negative values indicate that it took more time to reuse outputs
-            than it did to create them originally. May be `null` if the
-            information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_not_enabled
-            - cache-if_condition_not_matched
-            - disabled_to_ensure_correctness
-            - do-not-cache-if_condition_matched
-            - multiple_outputs_declared
-            - no_outputs_declared
-            - non_cacheable_inputs
-            - non_cacheable_task_action
-            - non_cacheable_task_implementation
-            - non_cacheable_tree_output
-            - overlapping_outputs
-            - task_has_no_actions
-            - task_output_caching_not_enabled
-            - unknown
-          description: >
-            The category of the non-cacheability reason:
-              * `build_cache_not_enabled` - Caching has not been enabled for the build
-              * `cache-if_condition_not_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#cacheIf`
-              * `disabled_to_ensure_correctness` - The task failed validation. Available since Gradle 7.0
-              * `do-not-cache-if_condition_matched` - Caching was disabled for the task via `org.gradle.api.tasks.TaskOutputs#doNotCacheIf`
-              * `multiple_outputs_declared` - The task declared multiple outputs
-              * `no_outputs_declared` - The task had no outputs declared
-              * `non_cacheable_inputs` - One of the task inputs was not cacheable, either because some type used as an input to the task was loaded via a custom classloader, or a Java lambda was used as an input. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_action` - One of the task actions was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_task_implementation` - The task implementation was not cacheable, either because it was loaded via a custom classloader, or a Java lambda was used to implement it. Available since Gradle 5.0 and before Gradle 7.5
-              * `non_cacheable_tree_output` - The task had a `org.gradle.api.file.FileTree` or a `org.gradle.api.internal.file.collections.DirectoryFileTree` as an output. Available since Gradle 5.0
-              * `overlapping_outputs` - The tasks outputs overlapped with another task. As Gradle cannot safely determine which task each output file belongs to, it disabled caching            
-              * `task_has_no_actions` - The task did not declare any actions
-              * `task_output_caching_not_enabled` - Caching has not been enabled for the task
-              * `unknown` - Reason for disabled caching was not known
-
-            May be `null` when the task was cacheable or if the information was
-            not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: >-
-            The human-readable reason for a non-cacheable task. May be `null`
-            when the task was cacheable or if the information was not available.
-          x-nullable: true
-    GradleBuildCachePerformanceTaskExecution:
-      type: array
-      description: A list of executed tasks with performance related information.
-      items:
-        $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecutionEntry'
-    GradleBuildCachePerformanceTaskFingerprintingSummary:
-      type: object
-      description: >-
-        A summary of task fingerprinting. Fingerprinted tasks are part of the
-        `taskExecution.avoidedTasks` or `taskExecution.executedTasks`, or
-        `taskExecution.noSourceTasks` buckets. May be `null` if Gradle version
-        is < `5.0` or Gradle Enterprise Gradle plugin version is < `2.1`.
-      x-nullable: true
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted tasks.
-        serialDuration:
-          type: integer
-          format: int64
-          description: >-
-            Sum of all fingerprinting times of fingerprinted tasks in
-            milliseconds.
-    GradleBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - upToDate
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: >-
-            The ratio of the total avoidance savings against the potential
-            serial execution time (which is the actual serial execution time
-            plus the total avoidance savings). Quantifies the effect of
-            avoidance savings in this build. The bigger the ratio is, the more
-            time was saved when running the build.
-        upToDate:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            build incrementalism in milliseconds.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused from the local build cache in
-            milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the tasks due to
-            their outputs being reused from the remote build cache in
-            milliseconds.
-    GradleBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: Information about the local build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: >-
-            Whether pushing to the local build cache was enabled.  May be `null`
-            if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: >-
-            Whether the local cache was disabled due to an error occuring in
-            loading or storing local build cache entries.
-        directory:
-          type: string
-          description: >-
-            Location of the local build cache. Can be relative or absolute
-            depending on its value. May be `null` if the local build cache is
-            disabled.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: Information about the remote build cache used in the build.
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: >-
-            Whether pushing to the remote build cache was enabled. May be `null`
-            if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: >-
-            Wether the remote build cache was disabled during the build due to
-            an error occuring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: >-
-            URL of the remote build cache. May be `null` if the remote build
-            cache is disabled.
-          x-nullable: true
-    GradleBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    GradleBuildCachePerformanceBuildCaches:
-      type: object
-      description: >-
-        Information about the local and remote build caches used in the build.
-        May be `null` if the build cache is globally disabled.
-      x-nullable: true
-      required:
-        - local
-        - remote
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCacheOverhead'
-    GradleBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Gradle Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveTaskExecutionTime
-        - serialTaskExecutionTime
-        - serializationFactor
-        - taskExecution
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveTaskExecutionTime:
-          type: integer
-          format: int64
-          description: >-
-            Wall clock time spent executing tasks in milliseconds. It is the
-            time spent between the start of the first task in the execution
-            phase and the end of the last task of the execution phase, removing
-            any interval where no task is being executed.
-        serialTaskExecutionTime:
-          type: integer
-          format: int64
-          description: >-
-            Wall clock time of all task executions in milliseconds. It is the
-            sum of all individual task durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: >-
-            The ratio of `serialTaskExecutionTime` over the
-            `effectiveTaskExecutionTime`. Quantifies the effect of task
-            parallelization. A value equal to `1` means that no parallelization
-            occurred. A value greater than `1` means that tasks were executed
-            faster due to parallelization.
-        taskExecution:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceTaskExecution'
-        taskFingerprintingSummary:
-          $ref: >-
-            #/components/schemas/GradleBuildCachePerformanceTaskFingerprintingSummary
-        avoidanceSavingsSummary:
-          $ref: >-
-            #/components/schemas/GradleBuildCachePerformanceAvoidanceSavingsSummary
-        buildCaches:
-          $ref: '#/components/schemas/GradleBuildCachePerformanceBuildCaches'
-    MavenBuildCachePerformanceGoalExecutionEntry:
-      type: object
-      required:
-        - goalName
-        - mojoType
-        - goalExecutionId
-        - goalProjectName
-        - avoidanceOutcome
-        - duration
-      properties:
-        goalName:
-          type: string
-          description: The goal name.
-        mojoType:
-          type: string
-          description: >-
-            The fully qualified class name of the Mojo that provides the
-            implementation of this goal.
-        goalExecutionId:
-          type: string
-          description: The goal execution ID.
-        goalProjectName:
-          type: string
-          description: The goal project name.
-        avoidanceOutcome:
-          type: string
-          enum:
-            - avoided_from_local_cache
-            - avoided_from_remote_cache
-            - executed_cacheable
-            - executed_not_cacheable
-            - executed_unknown_cacheability
-            - skipped
-          description: |
-            The avoidance outcome of this task with respect to performance:
-              * `avoided_from_local_cache` - Goal whose execution was avoided due to reusing a local build cache entry
-              * `avoided_from_remote_cache` - Goal whose execution was avoided due to reusing a remote build cache entry
-              * `executed_cacheable` - Goal which was executed but was cacheable
-              * `executed_not_cacheable` - Goal which was executed but was not cacheable
-              * `executed_unknown_cacheability` - Goal which was executed and whose cacheability could not be determined
-              * `skipped` - Skipped goal
-        duration:
-          type: integer
-          format: int64
-          description: The goal duration in milliseconds.
-        fingerprintingDuration:
-          type: integer
-          format: int64
-          description: >-
-            The goal fingerprinting duration in milliseconds. This duration is
-            part of the complete task execution duration. May be `null` if the
-            goal was not fingerprinted.
-          x-nullable: true
-        avoidanceSavings:
-          type: integer
-          format: int64
-          description: >-
-            The goal avoidance savings in milliseconds, which can be negative.
-            Negative values indicate that it took more time to reuse outputs
-            than it did to create them originally. May be `null` if the
-            information was not available.
-          x-nullable: true
-        nonCacheabilityCategory:
-          type: string
-          enum:
-            - build_cache_disabled_by_user
-            - goal_execution_marked_non_cacheable
-            - goal_not_supported
-            - no_gradle_enterprise_server_configured
-            - non_clean_build
-            - not_entitled
-            - offline_build
-            - unknown
-            - unknown_entitlements
-          description: >
-            The category of the non-cacheability reason:
-              * `build_cache_disabled_by_user` - The build cache was disabled by the user
-              * `goal_execution_marked_non_cacheable` - The goal execution was marked as non-cacheable
-              * `goal_not_supported` - The goal did not support build caching
-              * `no_gradle_enterprise_server_configured` - No Gradle Enterprise server was configured
-              * `non_clean_build` - The `clean` lifecycle was not executed 
-              * `not_entitled` - The Gradle Enterprise license entitlements did not allow Maven build caching
-              * `offline_build` - The build was run in offline mode
-              * `unknown` - Reason for disabled caching was not known
-              * `unknown_entitlements` - The Gradle Enterprise license entitlements could not be checked
-
-            May be `null` when the goal execution was cacheable or if the
-            information was not available.
-          x-nullable: true
-        nonCacheabilityReason:
-          type: string
-          description: >-
-            The human-readable reason for a non-cacheable goal execution. May be
-            `null` when the goal execution was cacheable or if the information
-            was not available.
-          x-nullable: true
-    MavenBuildCachePerformanceGoalExecution:
-      type: array
-      description: A list of executed goals with performance related information.
-      items:
-        $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecutionEntry'
-    MavenBuildCachePerformanceGoalFingerprintingSummary:
-      type: object
-      description: >-
-        A summary of goal fingerprinting. Fingerprinted goals are part of the
-        `goalExecution.avoidedGoals` or `goalExecution.executedGoals` buckets.
-      required:
-        - count
-        - serialDuration
-      properties:
-        count:
-          type: integer
-          description: Count of fingerprinted goals.
-        serialDuration:
-          type: integer
-          format: int64
-          description: >-
-            Sum of all fingerprinting times of fingerprinted goals in
-            milliseconds.
-    MavenBuildCachePerformanceAvoidanceSavingsSummary:
-      type: object
-      description: A breakdown of avoidance savings.
-      required:
-        - total
-        - ratio
-        - localBuildCache
-        - remoteBuildCache
-      properties:
-        total:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused in milliseconds.
-        ratio:
-          type: number
-          format: double
-          description: >-
-            The ratio of the total avoidance savings against the potential
-            serial execution time (which is the actual serial execution time
-            plus the total avoidance savings). Quantifies the effect of
-            avoidance savings in this build. The bigger the ratio is, the more
-            time was saved when running the build.
-        localBuildCache:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused from the local build cache in
-            milliseconds.
-        remoteBuildCache:
-          type: integer
-          format: int64
-          description: >-
-            The estimated reduction in serial execution time of the goals due to
-            their outputs being reused from the remote build cache in
-            milliseconds.
-    MavenBuildCachePerformanceBuildCacheLocalInfo:
-      type: object
-      description: >-
-        Information about the local build cache used in the build, if it was
-        configured in the build. May be `null` if the local build cache is not
-        configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the local build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: >-
-            Whether pushing to the local build cache was enabled. May be `null`
-            if the local build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: >-
-            Whether the local cache was disabled due to an error occuring in
-            loading or storing local build cache entries.
-        directory:
-          type: string
-          description: >-
-            Location of the local build cache. Can be relative or absolute
-            depending on its value. May be `null` if the local build cache is
-            disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheRemoteInfo:
-      type: object
-      description: >-
-        Information about the remote build cache used in the build, if it was
-        configured in the build. May be `null` if the remote build cache is not
-        configured.
-      x-nullable: true
-      required:
-        - isEnabled
-        - isDisabledDueToError
-      properties:
-        isEnabled:
-          type: boolean
-          description: Whether the remote build cache was enabled.
-        isPushEnabled:
-          type: boolean
-          description: >-
-            Whether pushing to the remote build cache was enabled. May be `null`
-            if the remote build cache is disabled.
-          x-nullable: true
-        isDisabledDueToError:
-          type: boolean
-          description: >-
-            Whether the remote build cache was disabled during the build due to
-            an error occuring in loading or storing remote build cache entries.
-        url:
-          type: string
-          description: >-
-            URL of the remote build cache. May be `null` if the remote build
-            cache is disabled.
-          x-nullable: true
-    MavenBuildCachePerformanceBuildCacheOverhead:
-      type: object
-      description: Information about the build cache overhead in this build.
-      required:
-        - uploading
-        - downloading
-        - packing
-        - unpacking
-      properties:
-        uploading:
-          type: integer
-          format: int64
-          description: Overhead of upload operations in milliseconds.
-        downloading:
-          type: integer
-          format: int64
-          description: Overhead of download operations in milliseconds.
-        packing:
-          type: integer
-          format: int64
-          description: Overhead of pack operations in milliseconds.
-        unpacking:
-          type: integer
-          format: int64
-          description: Overhead of unpack operations in milliseconds.
-    MavenBuildCachePerformanceBuildCaches:
-      type: object
-      description: >-
-        Information about the local and remote build caches used in the build,
-        if it was configured in the build. May be `null` if the build cache
-        configuration could not be captured (e.g. very early build failure).
-      x-nullable: true
-      required:
-        - overhead
-      properties:
-        local:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheLocalInfo'
-        remote:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheRemoteInfo'
-        overhead:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCacheOverhead'
-    MavenBuildCachePerformance:
-      type: object
-      description: The build cache performance of a Maven Build Scan.
-      required:
-        - id
-        - buildTime
-        - effectiveProjectExecutionTime
-        - serialProjectExecutionTime
-        - serializationFactor
-        - goalExecution
-        - goalFingerprintingSummary
-        - avoidanceSavingsSummary
-      properties:
-        id:
-          type: string
-          description: The Build Scan ID.
-        buildTime:
-          type: integer
-          format: int64
-          description: Wall clock duration of the build in milliseconds.
-        effectiveProjectExecutionTime:
-          type: integer
-          format: int64
-          description: >-
-            Wall clock time spent executing projects in milliseconds. It is the
-            time spent between the start of the first project execution and the
-            end of the last project execution, removing any interval where no
-            project is being executed.
-        serialProjectExecutionTime:
-          type: integer
-          format: int64
-          description: >-
-            Wall clock time of all project executions in milliseconds. It is the
-            sum of all individual project durations.
-        serializationFactor:
-          type: number
-          format: double
-          description: >-
-            The ratio of `serialProjectExecutionTime` over the
-            `effectiveProjectExecutionTime`. Quantifies the effect of project
-            parallelization. A value equal to `1` means that no parallelization
-            occurred. A value greater than `1` means that projects were executed
-            faster due to parallelization.
-        goalExecution:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceGoalExecution'
-        goalFingerprintingSummary:
-          $ref: >-
-            #/components/schemas/MavenBuildCachePerformanceGoalFingerprintingSummary
-        avoidanceSavingsSummary:
-          $ref: >-
-            #/components/schemas/MavenBuildCachePerformanceAvoidanceSavingsSummary
-        buildCaches:
-          $ref: '#/components/schemas/MavenBuildCachePerformanceBuildCaches'
-    ReplicationConfiguration:
-      description: >-
-        Cached data replication configuration description. May be `null` if
-        replication is not configured.
-      type: object
-      x-nullable: true
-      required:
-        - source
-        - preemptive
-      properties:
-        source:
-          type: string
-          description: The name of the Build Cache Node which is the source of data.
-        preemptive:
-          type: boolean
-          description: Indicates if preemptive replication is enabled from the source.
-    NodeConfiguration:
-      description: A Build Cache Node configuration description.
-      type: object
-      required:
-        - enabled
-      properties:
-        enabled:
-          type: boolean
-          description: Indicates if the Build Cache Node is enabled.
-        replication:
-          $ref: '#/components/schemas/ReplicationConfiguration'
-    KeySecretPair:
-      description: A Build Cache Node key and secret pair.
-      type: object
-      required:
-        - key
-        - secret
-      properties:
-        key:
-          type: string
-          description: A unique identifier for the Build Cache Node in Gradle Enterprise.
-        secret:
-          type: string
-          description: The secret associated with the Build Cache Node.
-  examples:
-    BuildDeletedApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-deleted
-        title: Build deleted.
-        detail: |
-          Build 9r4d13f0r3v3r has been deleted and is no longer available.
-        status: 400
-    NonApplicableModelApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-model-not-applicable
-        title: Build model is not applicable.
-        detail: >
-          Build model BuildCachePerformance is not available for build
-          9r4d13f0r3v3r because the build agent version is not supported.
-        status: 400
-    RequestValidationApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:validation
-        title: Request validation failed.
-        detail: >
-          Numeric instance is lower than the required minimum (minimum: 1,
-          found: 0) (Additional info: Query parameter: maxWaitSecs).
-        status: 400
-    NotFoundApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:not-found
-        title: >-
-          The requested resource is not found or the permissions to know about
-          it are missing.
-        status: 404
-    UnexpectedErrorApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:unexpected-error
-        title: Encountered an internal server error.
-        detail: |
-          The ingestion of build 9r4d13f0r3v3r failed.
-        status: 500
-    IngestionNotCompletedApiProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:build-processing-incomplete
-        title: Build processing is incomplete.
-        detail: >
-          The data of build 9r4d13f0r3v3r is not yet available for viewing.
-          Please try again later.
-        status: 503
-    NodeNotSignedInProblemExample:
-      value:
-        type: urn:gradle:enterprise:api:problems:node-not-signed-in
-        title: >-
-          Node with name not-signed-in-node1 must be signed-in before this
-          operation can be performed.
-        status: 503
-tags:
-  - name: Builds
-    description: >
-      Endpoints related to retrieving details of a Build Scan of the Gradle
-      Enterprise instance. 
-
-      To access these endpoints the user requires the `Access build data via the
-      API` permission.
-  - name: BuildCache
-    x-displayName: Build Cache
-    description: >
-      Endpoints related to configuring the Build Cache nodes of the Gradle
-      Enterprise instance. 
-
-      To access these endpoints the user requires the `Configure build caches`
-      permission.
-  - name: GradleEnterprise
-    x-traitTag: true
-    description: All endpoints of the Gradle Enterprise API.

From 2b22e09c5c1e3222b57b05292591fd903114b1b5 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 08:18:19 +0200
Subject: [PATCH 36/57] Remove OpenApi references from the cmdline module

---
 .../build.gradle.kts                          | 41 -------------------
 1 file changed, 41 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
index 4d87f9fb..18ced93c 100644
--- a/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
+++ b/components/fetch-build-scan-data-cmdline-tool/build.gradle.kts
@@ -5,7 +5,6 @@ plugins {
     id("java")
     id("jvm-test-suite")
     id("com.github.johnrengelman.shadow") version "8.1.1"
-    id("org.openapi.generator") version "6.6.0"
 }
 
 description = "Application to fetch build scan data using the Gradle Enterprise Export API"
@@ -19,18 +18,6 @@ dependencies {
     implementation(project(":build-scan-data-loader-online"))
     implementation(project(":build-scan-data-loader-offline"))
 
-    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.11.0"))
-    implementation("com.squareup.okhttp3:okhttp")
-    implementation("com.squareup.okhttp3:okhttp-tls")
-    implementation("com.squareup.okhttp3:logging-interceptor")
-
-    implementation("io.swagger:swagger-annotations:1.6.10")
-    implementation("io.gsonfire:gson-fire:1.8.5")
-    implementation("javax.ws.rs:jsr311-api:1.1.1")
-    implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
-
-    implementation("javax.annotation:javax.annotation-api:1.3.2")
-    implementation("com.google.guava:guava:31.1-jre")
     implementation("info.picocli:picocli:4.7.3")
     annotationProcessor("info.picocli:picocli-codegen:4.7.3")
 }
@@ -46,34 +33,6 @@ val test by testing.suites.getting(JvmTestSuite::class) {
     useJUnitJupiter()
 }
 
-openApiGenerate {
-    generatorName.set("java")
-    inputSpec.set("$projectDir/src/main/openapi/openapi.yaml")
-    outputDir.set("$buildDir/generated/gradle_enterprise_api")
-    ignoreFileOverride.set("$projectDir/.openapi-generator-ignore")
-    modelPackage.set("com.gradle.enterprise.api.model")
-    apiPackage.set("com.gradle.enterprise.api")
-    invokerPackage.set("com.gradle.enterprise.api.client")
-    // see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/java.md for a description of each configuration option
-    configOptions.set(mapOf(
-            "library" to "okhttp-gson",
-            "dateLibrary" to "java8",
-            "hideGenerationTimestamp" to "true",
-            "openApiNullable" to "false",
-            "useBeanValidation" to "false",
-            "disallowAdditionalPropertiesIfNotPresent" to "false",
-            "sourceFolder" to ""  // makes IDEs like IntelliJ more reliably interpret the class packages.
-    ))
-}
-
-sourceSets {
-    main {
-        java {
-            srcDir(tasks.openApiGenerate)
-        }
-    }
-}
-
 tasks.withType(JavaCompile::class).configureEach {
     options.compilerArgs.add("-Aproject=${project.group}/${project.name}")
     options.encoding = "UTF-8"

From 8d697376b663cc3d361212528754203c77ed6794 Mon Sep 17 00:00:00 2001
From: Etienne Studer <etienne@gradle.com>
Date: Fri, 12 May 2023 08:21:12 +0200
Subject: [PATCH 37/57] Declare mavenCentral

---
 components/build-scan-data-loader-offline/build.gradle.kts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index 2f228a7a..969a385a 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -2,6 +2,10 @@ plugins {
     id("java-library")
 }
 
+repositories {
+    mavenCentral()
+}
+
 dependencies {
     api(project(":build-scan-data-loader-api"))
     "runtimeOnly"(files("build-scan-dump-reader.jar"))

From 4f4b9f580f155d34f17f18cf4aa1016e2bf4ef99 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Fri, 12 May 2023 10:24:29 +0200
Subject: [PATCH 38/57] Use the same CLI for reading online Build Scans and
 Build Scan dumps

---
 components/scripts/lib/build-scan-offline.sh | 21 +++++++++-----------
 components/scripts/lib/build-scan-online.sh  |  8 ++++++--
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/components/scripts/lib/build-scan-offline.sh b/components/scripts/lib/build-scan-offline.sh
index 9f3b3f1a..632af62a 100644
--- a/components/scripts/lib/build-scan-offline.sh
+++ b/components/scripts/lib/build-scan-offline.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 
 readonly GRADLE_ENTERPRISE_LICENSE="${SCRIPT_DIR}/gradle-enterprise.license"
-readonly READ_BUILD_SCAN_DATA_JAR="${LIB_DIR}/build-scan-clients/read-build-scan-data-cmdline-tool-${SCRIPT_VERSION}-all.jar"
+readonly BUILD_SCAN_DUMP_READER_JAR="${LIB_DIR}/build-scan-clients/build-scan-dump-reader.jar"
 
 build_scan_dumps=()
 
@@ -9,8 +9,8 @@ verify_offline_mode_required_files_exist() {
   if [ ! -f "$GRADLE_ENTERPRISE_LICENSE" ]; then
     die "ERROR: Missing required file gradle-enterprise.license in the root folder of the build validation scripts" "${INVALID_INPUT}"
   fi
-  if [ ! -f "$READ_BUILD_SCAN_DATA_JAR" ]; then
-    die "ERROR: Missing required file to read the build scan data" "${INVALID_INPUT}"
+  if [ ! -f "$BUILD_SCAN_DUMP_READER_JAR" ]; then
+    die "ERROR: Missing required file to read the Build Scan data" "${INVALID_INPUT}"
   fi
 }
 
@@ -38,18 +38,15 @@ find_build_scan_dump() {
 }
 
 read_build_scan_dumps() {
-  local build_scan_data args
-  args=()
+  local build_scan_data build_scan_dump_urls
+  build_scan_dump_urls=()
 
-  args+=(
-      "extract"
-      "--license-file" "${SCRIPT_DIR}/gradle-enterprise.license"
-      "0,${build_scan_dumps[0]}"
-      "1,${build_scan_dumps[1]}"
-  )
+  for run_num in "${!build_scan_dumps[@]}"; do
+    build_scan_dump_urls+=( "file://${build_scan_dumps[run_num]}" )
+  done
 
   echo "Extracting Build Scan data for all builds"
-  if ! build_scan_data="$(invoke_java "$READ_BUILD_SCAN_DATA_JAR" "${args[@]}")"; then
+  if ! build_scan_data="$(fetch_build_scan_data 'brief_logging' "${build_scan_dump_urls[@]}")"; then
     exit "$UNEXPECTED_ERROR"
   fi
   echo "Finished extracting Build Scan data for all builds"
diff --git a/components/scripts/lib/build-scan-online.sh b/components/scripts/lib/build-scan-online.sh
index 41be1822..39d43aac 100644
--- a/components/scripts/lib/build-scan-online.sh
+++ b/components/scripts/lib/build-scan-online.sh
@@ -77,9 +77,11 @@ fetch_build_scans_and_build_time_metrics() {
 # Note: Callers of this function require stdout to be clean. No logging can be
 #       done inside this function.
 fetch_build_scan_data() {
-  local logging_level="$1"
+  local logging_level build_scan_urls args
+  args=()
+  logging_level="$1"
   shift
-  local build_scan_urls=("$@")
+  build_scan_urls=("$@")
 
   if [[ "${debug_mode}" == "on" ]]; then
     args+=("--debug")
@@ -97,6 +99,8 @@ fetch_build_scan_data() {
     args+=("--brief-logging")
   fi
 
+  args+=("--license-file" "${GRADLE_ENTERPRISE_LICENSE}")
+
   for run_num in "${!build_scan_urls[@]}"; do
     args+=( "${run_num},${build_scan_urls[run_num]}" )
   done

From ad98270bed0374a846db94ed54f0dc0c0a1bae87 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Fri, 12 May 2023 10:48:47 +0200
Subject: [PATCH 39/57] Add --license-file argument to the Build Scan data
 fetch CLI

---
 .../enterprise/api/client/GradleEnterpriseApiClient.java     | 5 +++--
 .../com/gradle/enterprise/cli/FetchBuildScanDataCommand.java | 5 ++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 760a07a5..9eeefc76 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -13,6 +13,7 @@
 import java.math.BigDecimal;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Path;
 import java.time.Duration;
 import java.util.AbstractMap;
 import java.util.Arrays;
@@ -33,11 +34,11 @@ public final class GradleEnterpriseApiClient {
     private final CustomValueNames customValueNames;
     private final BuildScanDataLoader buildScanDataLoader;
 
-    public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Logger logger) {
+    public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Path licenseFile, Logger logger) {
         this.baseUrl = baseUrl;
         this.customValueNames = customValueNames;
         this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
-                ? OfflineBuildScanDataLoader.newInstance(null) // todo
+                ? OfflineBuildScanDataLoader.newInstance(licenseFile)
                 : new OnlineBuildScanDataLoader(logger);
     }
 
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index d4980633..82991d72 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -40,6 +40,9 @@ public static class ExitCode {
     @Parameters(paramLabel = "BUILD_SCAN", description = "The build scans to fetch. Each build scan URL is preceded by the run num that produced the build scan.", arity = "1..*")
     private List<String> runNumsAndBuildScanUrls;
 
+    @Option(names = {"--license-file"}, description = "Specifies the location of the Gradle Enterprise license.", required = true)
+    private Path licenseFile;
+
     @Option(names = {"--mapping-file"}, description = "Specifies a mapping file that configures the names used to fetch important custom values.")
     private Optional<Path> customValuesMappingFile;
 
@@ -85,7 +88,7 @@ private List<BuildScanData> fetchBuildScanData(List<NumberedBuildScan> buildScan
     private BuildScanData fetchBuildScanData(NumberedBuildScan buildScan, CustomValueNames customValueNames) {
         logStartFetchingBuildScanData(buildScan);
         try {
-            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(buildScan.baseUrl(), customValueNames, logger);
+            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(buildScan.baseUrl(), customValueNames, licenseFile, logger);
             BuildScanData data = apiClient.fetchBuildScanData(buildScan);
 
             logFinishedFetchingBuildScanData(buildScan);

From 9ff3c12cd8f5ab34571c59fe665f6a8be303897f Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Fri, 12 May 2023 11:01:33 +0200
Subject: [PATCH 40/57] Fix API client map

---
 .../gradle/enterprise/loader/OnlineBuildScanDataLoader.java    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 720ab314..3079d956 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -63,8 +63,7 @@ public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI re
 
     private synchronized GradleEnterpriseApiClient getOrCreateClient(URL buildScanUrl) {
         URL baseUrl = extractBaseUrl(buildScanUrl);
-        apiClientsByBaseUrl.computeIfAbsent(buildScanUrl.toString(), k -> new GradleEnterpriseApiClient(baseUrl, logger));
-        return apiClientsByBaseUrl.get(baseUrl.toString());
+        return apiClientsByBaseUrl.computeIfAbsent(baseUrl.toString(), k -> new GradleEnterpriseApiClient(baseUrl, logger));
     }
 
     private static URL toBuildScanURL(URI resource) {

From 84eef246570e3a17d4dd1bfddb247d808cd9dd9e Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Fri, 12 May 2023 17:48:50 +0200
Subject: [PATCH 41/57] Delete duplicate FailedRequestException

---
 .../api/client/FailedRequestException.java    | 39 -------------------
 .../cli/FetchBuildScanDataCommand.java        |  2 +-
 2 files changed, 1 insertion(+), 40 deletions(-)
 delete mode 100644 components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/FailedRequestException.java

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/FailedRequestException.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/FailedRequestException.java
deleted file mode 100644
index bdee3e3c..00000000
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/FailedRequestException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.gradle.enterprise.api.client;
-
-import java.net.URL;
-import java.util.Optional;
-
-public class FailedRequestException extends RuntimeException {
-
-    private final int httpStatusCode;
-
-    private final String responseBody;
-
-    public FailedRequestException(URL buildScanUrl, ApiException e) {
-        super(buildMessage(buildScanUrl, e.getCode()), e);
-        this.httpStatusCode = e.getCode();
-        this.responseBody = e.getResponseBody();
-    }
-
-    public int httpStatusCode() {
-        return httpStatusCode;
-    }
-
-    public Optional<String> getResponseBody() {
-        return Optional.ofNullable(responseBody);
-    }
-
-    private static String buildMessage(URL buildScanUrl, int code) {
-        switch (code) {
-            case 404:
-                return String.format("Build scan %s was not found.%nVerify the build scan exists and you have been " +
-                        "granted the permission 'Access build data via the API'.", buildScanUrl);
-            case 401:
-                return String.format("Failed to authenticate while attempting to fetch build scan %s", buildScanUrl);
-            case 0:
-                return String.format("Unable to connect to server to fetch build scan %s", buildScanUrl);
-            default:
-                return String.format("Encountered an unexpected response while fetching build scan %s", buildScanUrl);
-        }
-    }
-}
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index 82991d72..a50859eb 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -1,7 +1,7 @@
 package com.gradle.enterprise.cli;
 
-import com.gradle.enterprise.api.client.FailedRequestException;
 import com.gradle.enterprise.api.client.GradleEnterpriseApiClient;
+import com.gradle.enterprise.loader.FailedRequestException;
 import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;

From 235c0ea35c69670fef02398b6e4dbd9cc4f937fe Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:07:43 +0200
Subject: [PATCH 42/57] Remove explicit runtime dependency on the
 build-scan-dump-reader jar

---
 components/build-scan-data-loader-offline/build.gradle.kts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index 969a385a..d7783ef8 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -8,7 +8,6 @@ repositories {
 
 dependencies {
     api(project(":build-scan-data-loader-api"))
-    "runtimeOnly"(files("build-scan-dump-reader.jar"))
 }
 
 java {

From 881c4527665e4ca186433eb6b77dbb603e1aca6f Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:30:30 +0200
Subject: [PATCH 43/57] Rename Pair to BuildScanData and add
 gradleEnterpriseServerURL

---
 .../loader/BuildScanDataLoader.java           | 35 ++++++++++++++-----
 .../loader/OfflineBuildScanDataLoader.java    |  4 +--
 .../loader/ReflectiveBuildScanDumpReader.java | 13 +++----
 .../loader/GradleEnterpriseApiClient.java     | 23 ++++++++----
 .../loader/OnlineBuildScanDataLoader.java     |  4 +--
 .../api/client/GradleEnterpriseApiClient.java | 19 +++++-----
 6 files changed, 64 insertions(+), 34 deletions(-)

diff --git a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
index 2571d7d7..c633b28e 100644
--- a/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
+++ b/components/build-scan-data-loader-api/src/main/java/com/gradle/enterprise/loader/BuildScanDataLoader.java
@@ -5,29 +5,48 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
+import java.net.MalformedURLException;
 import java.net.URI;
+import java.net.URL;
+import java.util.Optional;
 
 public interface BuildScanDataLoader {
 
     BuildToolType determineBuildToolType(URI resource);
 
+    // TODO add static factory method to build the BuildScanDataLoader
+
     // todo in online mode, fetch the two models in parallel (for both Gradle and Maven)
-    Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource);
+    BuildScanData<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource);
+
+    BuildScanData<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource);
 
-    Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource);
+    static
 
     enum BuildToolType {GRADLE, MAVEN}
 
-    final class Pair<S, T> {
+    final class BuildScanData<A, B> {
 
-        public final S first;
-        public final T second;
+        public final Optional<URI> gradleEnterpriseServerUri;
+        public final A attributes;
+        public final B buildCachePerformance;
 
-        public Pair(S first, T second) {
-            this.first = first;
-            this.second = second;
+        public BuildScanData(Optional<URI> gradleEnterpriseServerUri, A attributes, B buildCachePerformance) {
+            this.gradleEnterpriseServerUri = gradleEnterpriseServerUri;
+            this.attributes = attributes;
+            this.buildCachePerformance = buildCachePerformance;
         }
 
+        public Optional<URL> gradleEnterpriseServerURL() {
+            return gradleEnterpriseServerUri.map(u -> {
+                try {
+                    return u.toURL();
+                } catch (MalformedURLException e) {
+                    // Should never get here
+                    throw new RuntimeException(e);
+                }
+            });
+        }
     }
 
 }
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
index 2a1c5d30..fb159ded 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
@@ -27,12 +27,12 @@ public BuildToolType determineBuildToolType(URI resource) {
     }
 
     @Override
-    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
+    public BuildScanData<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
         return reader.readGradleBuildScanDump(Paths.get(resource));
     }
 
     @Override
-    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
+    public BuildScanData<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
         return reader.readMavenBuildScanDump(Paths.get(resource));
     }
 
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
index 3513a09f..946adaa9 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
@@ -4,12 +4,13 @@
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
-import com.gradle.enterprise.loader.BuildScanDataLoader.Pair;
+import com.gradle.enterprise.loader.BuildScanDataLoader.BuildScanData;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
+import java.util.Optional;
 
 import static com.gradle.enterprise.loader.BuildScanDataLoader.*;
 
@@ -50,7 +51,7 @@ BuildToolType readBuildToolType(Path scanDump) {
         }
     }
 
-    Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
+    BuildScanData<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path scanDump) {
         try {
             Method extractGradleBuildScanDump = buildScanDumpReader.getClass().getMethod("readGradleBuildScanDump", Path.class);
             Object gradleBuild = extractGradleBuildScanDump.invoke(buildScanDumpReader, scanDump);
@@ -58,7 +59,7 @@ Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path
             GradleAttributes attributes = (GradleAttributes) gradleBuild.getClass().getField("attributes").get(gradleBuild);
             GradleBuildCachePerformance buildCachePerformance = (GradleBuildCachePerformance) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild);
 
-            return new Pair<>(attributes, buildCachePerformance);
+            return new BuildScanData<>(Optional.empty(), attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
@@ -68,7 +69,7 @@ Pair<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScanDump(Path
     }
 
     @SuppressWarnings({"WeakerAccess", "unused"})
-    Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path scanDump) {
+    BuildScanData<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path scanDump) {
         try {
             Method extractMavenBuildScanDump = buildScanDumpReader.getClass().getMethod("readMavenBuildScanDump", Path.class);
             Object mavenBuild = extractMavenBuildScanDump.invoke(buildScanDumpReader, scanDump);
@@ -76,7 +77,7 @@ Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path sc
             MavenAttributes attributes = (MavenAttributes) mavenBuild.getClass().getField("attributes").get(mavenBuild);
             MavenBuildCachePerformance buildCachePerformance = (MavenBuildCachePerformance) mavenBuild.getClass().getField("buildCachePerformance").get(mavenBuild);
 
-            return new Pair<>(attributes, buildCachePerformance);
+            return new BuildScanData<>(Optional.empty(), attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
             // We know that the real BuildScanDumpReader can only throw runtime exceptions (no checked exceptions are declared)
             throw (RuntimeException) e.getCause();
@@ -88,7 +89,7 @@ Pair<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDump(Path sc
     // TODO Remove
     public static void main(String[] args) {
         ReflectiveBuildScanDumpReader extractor = ReflectiveBuildScanDumpReader.newInstance(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise.aux.prod.license"));
-        Pair<GradleAttributes, GradleBuildCachePerformance> result = extractor.readGradleBuildScanDump(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise-gradle-build-validation/.data/02-validate-local-build-caching-same-location/20230511T111441-645cb201/second-build_ge-solutions/sample-projects/gradle/8.x/no-ge/build-scan-8.0.2-3.12.6-1683796487697-104c8ac5-cf01-4eb6-8b2d-f447d4803249.scan"));
+        BuildScanData<GradleAttributes, GradleBuildCachePerformance> result = extractor.readGradleBuildScanDump(FileSystems.getDefault().getPath("/Users/jhurne/Projects/road-tests/build-validation/gradle-enterprise-gradle-build-validation/.data/02-validate-local-build-caching-same-location/20230511T111441-645cb201/second-build_ge-solutions/sample-projects/gradle/8.x/no-ge/build-scan-8.0.2-3.12.6-1683796487697-104c8ac5-cf01-4eb6-8b2d-f447d4803249.scan"));
         System.out.println("Successfully fetched build scan dump data: " + result);
     }
 
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
index 868c90c0..e0a4e437 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
@@ -4,15 +4,17 @@
 import com.gradle.enterprise.api.client.ApiClient;
 import com.gradle.enterprise.api.client.ApiException;
 import com.gradle.enterprise.api.model.*;
-import com.gradle.enterprise.loader.BuildScanDataLoader.Pair;
+import com.gradle.enterprise.loader.BuildScanDataLoader.BuildScanData;
 import okhttp3.Credentials;
 import okhttp3.OkHttpClient;
 import okhttp3.tls.HandshakeCertificates;
 
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.time.Duration;
 import java.time.format.DateTimeParseException;
 import java.util.Locale;
+import java.util.Optional;
 
 public class GradleEnterpriseApiClient {
 
@@ -99,18 +101,27 @@ public String fetchBuildToolType(String buildScanId) throws ApiException {
         return build.getBuildToolType();
     }
 
-    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(String buildScanId) throws ApiException {
+    public BuildScanData<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(String buildScanId) throws ApiException {
         GradleAttributes attributes = apiClient.getGradleAttributes(buildScanId, null);
         GradleBuildCachePerformance buildCachePerformance = apiClient.getGradleBuildCachePerformance(buildScanId, null);
 
-        return new Pair<>(attributes, buildCachePerformance);
+        try {
+            return new BuildScanData<>(Optional.of(baseUrl.toURI()), attributes, buildCachePerformance);
+        } catch (URISyntaxException e) {
+            // Should never get here
+            throw new RuntimeException(e);
+        }
     }
 
-    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(String buildScanId) throws ApiException {
+    public BuildScanData<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(String buildScanId) throws ApiException {
         MavenAttributes attributes = apiClient.getMavenAttributes(buildScanId, null);
         MavenBuildCachePerformance buildCachePerformance = apiClient.getMavenBuildCachePerformance(buildScanId, null);
 
-        return new Pair<>(attributes, buildCachePerformance);
+        try {
+            return new BuildScanData<>(Optional.of(baseUrl.toURI()), attributes, buildCachePerformance);
+        } catch (URISyntaxException e) {
+            // Should never get here
+            throw new RuntimeException(e);
+        }
     }
-
 }
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 3079d956..55cdd43d 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -36,7 +36,7 @@ public BuildToolType determineBuildToolType(URI resource) {
     }
 
     @Override
-    public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
+    public BuildScanData<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI resource) {
         URL buildScanUrl = toBuildScanURL(resource);
         GradleEnterpriseApiClient apiClient = getOrCreateClient(buildScanUrl);
         String buildScanId = extractBuildScanId(buildScanUrl);
@@ -49,7 +49,7 @@ public Pair<GradleAttributes, GradleBuildCachePerformance> loadDataForGradle(URI
     }
 
     @Override
-    public Pair<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
+    public BuildScanData<MavenAttributes, MavenBuildCachePerformance> loadDataForMaven(URI resource) {
         URL buildScanUrl = toBuildScanURL(resource);
         GradleEnterpriseApiClient apiClient = getOrCreateClient(buildScanUrl);
         String buildScanId = extractBuildScanId(buildScanUrl);
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 9eeefc76..348bf510 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -30,12 +30,10 @@
 
 public final class GradleEnterpriseApiClient {
 
-    private final URL baseUrl;
     private final CustomValueNames customValueNames;
     private final BuildScanDataLoader buildScanDataLoader;
 
     public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Path licenseFile, Logger logger) {
-        this.baseUrl = baseUrl;
         this.customValueNames = customValueNames;
         this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
                 ? OfflineBuildScanDataLoader.newInstance(licenseFile)
@@ -55,14 +53,15 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         }
     }
 
-    private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<GradleAttributes, GradleBuildCachePerformance> result) {
-        GradleAttributes attributes = result.first;
-        GradleBuildCachePerformance performance = result.second;
+    private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildScanDataLoader.BuildScanData<GradleAttributes, GradleBuildCachePerformance> result) {
+        GradleAttributes attributes = result.attributes;
+        GradleBuildCachePerformance performance = result.buildCachePerformance;
+
         return new BuildScanData(
                 runNum,
                 attributes.getRootProjectName(),
                 buildScanId,
-                baseUrl,
+                result.gradleEnterpriseServerURL().orElse(null),
                 findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),
@@ -75,14 +74,14 @@ private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildSc
         );
     }
 
-    private BuildScanData analyzeMavenBuild(int runNum, String buildScanId, BuildScanDataLoader.Pair<MavenAttributes, MavenBuildCachePerformance> result) {
-        MavenAttributes attributes = result.first;
-        MavenBuildCachePerformance performance = result.second;
+    private BuildScanData analyzeMavenBuild(int runNum, String buildScanId, BuildScanDataLoader.BuildScanData<MavenAttributes, MavenBuildCachePerformance> result) {
+        MavenAttributes attributes = result.attributes;
+        MavenBuildCachePerformance performance = result.buildCachePerformance;
         return new BuildScanData(
                 runNum,
                 attributes.getTopLevelProjectName(),
                 buildScanId,
-                baseUrl,
+                result.gradleEnterpriseServerURL().orElse(null),
                 findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitCommitIdKey(), attributes.getValues()),

From 4d3ac03e8d2f95ca2cca33153f8195488c9234d5 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:39:10 +0200
Subject: [PATCH 44/57] Extract BuildScanDataLoader creation to a static
 factory method

---
 .../api/client/GradleEnterpriseApiClient.java |  6 ++----
 .../cli/BuildScanDataLoaderFactory.java       | 21 +++++++++++++++++++
 .../cli/FetchBuildScanDataCommand.java        |  5 ++++-
 3 files changed, 27 insertions(+), 5 deletions(-)
 create mode 100644 components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 348bf510..33594732 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -33,11 +33,9 @@ public final class GradleEnterpriseApiClient {
     private final CustomValueNames customValueNames;
     private final BuildScanDataLoader buildScanDataLoader;
 
-    public GradleEnterpriseApiClient(URL baseUrl, CustomValueNames customValueNames, Path licenseFile, Logger logger) {
+    public GradleEnterpriseApiClient(CustomValueNames customValueNames, BuildScanDataLoader buildScanDataLoader) {
         this.customValueNames = customValueNames;
-        this.buildScanDataLoader = baseUrl.getProtocol().equals("file")
-                ? OfflineBuildScanDataLoader.newInstance(licenseFile)
-                : new OnlineBuildScanDataLoader(logger);
+        this.buildScanDataLoader = buildScanDataLoader;
     }
 
     public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
new file mode 100644
index 00000000..88d7ab5e
--- /dev/null
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
@@ -0,0 +1,21 @@
+package com.gradle.enterprise.cli;
+
+import com.gradle.enterprise.loader.BuildScanDataLoader;
+import com.gradle.enterprise.loader.Logger;
+import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
+import com.gradle.enterprise.loader.OnlineBuildScanDataLoader;
+
+import java.net.URI;
+import java.nio.file.Path;
+
+public class BuildScanDataLoaderFactory {
+    private BuildScanDataLoaderFactory() {
+
+    }
+
+    public static BuildScanDataLoader createBuildScanDataLoader(URI resource, Path licenseFile, Logger logger) {
+        return resource.getScheme().equals("file")
+            ? OfflineBuildScanDataLoader.newInstance(licenseFile)
+            : new OnlineBuildScanDataLoader(logger);
+    }
+}
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index a50859eb..38168dd0 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -19,6 +19,8 @@
 import java.util.concurrent.Callable;
 import java.util.stream.Collectors;
 
+import static com.gradle.enterprise.cli.BuildScanDataLoaderFactory.createBuildScanDataLoader;
+
 @Command(
     name = "fetch-build-scan-data-cmdline-tool",
     mixinStandardHelpOptions = true,
@@ -88,7 +90,8 @@ private List<BuildScanData> fetchBuildScanData(List<NumberedBuildScan> buildScan
     private BuildScanData fetchBuildScanData(NumberedBuildScan buildScan, CustomValueNames customValueNames) {
         logStartFetchingBuildScanData(buildScan);
         try {
-            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(buildScan.baseUrl(), customValueNames, licenseFile, logger);
+            // TODO can we create one of these for everyone?
+            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(customValueNames, createBuildScanDataLoader(buildScan.uri(), licenseFile, logger));
             BuildScanData data = apiClient.fetchBuildScanData(buildScan);
 
             logFinishedFetchingBuildScanData(buildScan);

From b6530d83d80d154b14278aeab849b8e195b6d1d3 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:40:26 +0200
Subject: [PATCH 45/57] Use the Build Scan ID from the returned build
 attributes

---
 .../api/client/GradleEnterpriseApiClient.java        | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 33594732..4ca44374 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -43,22 +43,22 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         String buildScanId = buildScan.buildScanId();
         BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.uri());
         if (buildToolType.equals(GRADLE)) {
-            return analyzeGradleBuild(runNum, buildScanId, buildScanDataLoader.loadDataForGradle(buildScan.uri()));
+            return analyzeGradleBuild(runNum, buildScanDataLoader.loadDataForGradle(buildScan.uri()));
         } else if (buildToolType.equals(MAVEN)) {
-            return analyzeMavenBuild(runNum, buildScanId, buildScanDataLoader.loadDataForMaven(buildScan.uri()));
+            return analyzeMavenBuild(runNum, buildScanDataLoader.loadDataForMaven(buildScan.uri()));
         } else {
             throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), buildToolType));
         }
     }
 
-    private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildScanDataLoader.BuildScanData<GradleAttributes, GradleBuildCachePerformance> result) {
+    private BuildScanData analyzeGradleBuild(int runNum, BuildScanDataLoader.BuildScanData<GradleAttributes, GradleBuildCachePerformance> result) {
         GradleAttributes attributes = result.attributes;
         GradleBuildCachePerformance performance = result.buildCachePerformance;
 
         return new BuildScanData(
                 runNum,
                 attributes.getRootProjectName(),
-                buildScanId,
+                attributes.getId(),
                 result.gradleEnterpriseServerURL().orElse(null),
                 findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),
@@ -72,13 +72,13 @@ private BuildScanData analyzeGradleBuild(int runNum, String buildScanId, BuildSc
         );
     }
 
-    private BuildScanData analyzeMavenBuild(int runNum, String buildScanId, BuildScanDataLoader.BuildScanData<MavenAttributes, MavenBuildCachePerformance> result) {
+    private BuildScanData analyzeMavenBuild(int runNum, BuildScanDataLoader.BuildScanData<MavenAttributes, MavenBuildCachePerformance> result) {
         MavenAttributes attributes = result.attributes;
         MavenBuildCachePerformance performance = result.buildCachePerformance;
         return new BuildScanData(
                 runNum,
                 attributes.getTopLevelProjectName(),
-                buildScanId,
+                attributes.getId(),
                 result.gradleEnterpriseServerURL().orElse(null),
                 findCustomValue(customValueNames.getGitRepositoryKey(), attributes.getValues()),
                 findCustomValue(customValueNames.getGitBranchKey(), attributes.getValues()),

From 0a01f39acf29b4dae6c77dba656df9305932906f Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:51:03 +0200
Subject: [PATCH 46/57] Extract Build Scan URL parsing methods to a new class
 and add tests

---
 .../build.gradle.kts                          |  5 +++
 .../enterprise/loader/BuildScanUrlUtils.java  | 39 +++++++++++++++++
 .../loader/OnlineBuildScanDataLoader.java     | 35 +--------------
 .../loader/BuildScanUrlUtilsTest.java         | 43 +++++++++++++++++++
 ...rmatTests.java => DurationFormatTest.java} |  2 +-
 5 files changed, 90 insertions(+), 34 deletions(-)
 create mode 100644 components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java
 create mode 100644 components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java
 rename components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/{DurationFormatTests.java => DurationFormatTest.java} (97%)

diff --git a/components/build-scan-data-loader-online/build.gradle.kts b/components/build-scan-data-loader-online/build.gradle.kts
index b6760dd5..60936f5c 100644
--- a/components/build-scan-data-loader-online/build.gradle.kts
+++ b/components/build-scan-data-loader-online/build.gradle.kts
@@ -1,5 +1,6 @@
 plugins {
     id("java-library")
+    id("jvm-test-suite")
 }
 
 repositories {
@@ -22,3 +23,7 @@ java {
         vendor.set(JvmVendorSpec.AZUL)
     }
 }
+
+val test by testing.suites.getting(JvmTestSuite::class) {
+    useJUnitJupiter()
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java
new file mode 100644
index 00000000..0525f94d
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java
@@ -0,0 +1,39 @@
+package com.gradle.enterprise.loader;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+public class BuildScanUrlUtils {
+    private BuildScanUrlUtils() {
+    }
+
+    public static URL toBuildScanURL(URI resource) {
+        try {
+            return resource.toURL();
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException(resource + " is not a valid Build Scan URL: " + e.getMessage(), e);
+        }
+    }
+
+    public static URL extractBaseUrl(URL buildScanUrl) {
+        String port = (buildScanUrl.getPort() != -1) ? ":" + buildScanUrl.getPort() : "";
+        return toURL(buildScanUrl.getProtocol() + "://" + buildScanUrl.getHost() + port);
+    }
+
+    public static String extractBuildScanId(URL buildScanUrl) {
+        String[] pathSegments = buildScanUrl.getPath().split("/");
+        if (pathSegments.length <= 2 || !pathSegments[1].equals("s")) {
+            throw new IllegalArgumentException("Invalid Build Scan URL: " + buildScanUrl);
+        }
+        return pathSegments[2];
+    }
+
+    private static URL toURL(String url) {
+        try {
+            return new URL(url);
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException("Invalid Build Scan URL: " + url, e);
+        }
+    }
+}
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
index 55cdd43d..daeec283 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
@@ -6,12 +6,13 @@
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
 
-import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
 
+import static com.gradle.enterprise.loader.BuildScanUrlUtils.*;
+
 public final class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
     // Use a String as the key because using a URL as a map key is dangerous (partly becuase URL is mutable).
@@ -65,36 +66,4 @@ private synchronized GradleEnterpriseApiClient getOrCreateClient(URL buildScanUr
         URL baseUrl = extractBaseUrl(buildScanUrl);
         return apiClientsByBaseUrl.computeIfAbsent(baseUrl.toString(), k -> new GradleEnterpriseApiClient(baseUrl, logger));
     }
-
-    private static URL toBuildScanURL(URI resource) {
-        try {
-            return resource.toURL();
-        } catch (MalformedURLException e) {
-            throw new IllegalArgumentException(resource + " is not a valid Build Scan URL: " + e.getMessage(), e);
-        }
-    }
-
-    //TODO duplicated in NumberedBuildScan
-    private static URL extractBaseUrl(URL buildScanUrl) {
-        String port = (buildScanUrl.getPort() != -1) ? ":" + buildScanUrl.getPort() : "";
-        return toURL(buildScanUrl.getProtocol() + "://" + buildScanUrl.getHost() + port);
-    }
-
-    //TODO duplicated in NumberedBuildScan
-    private static String extractBuildScanId(URL buildScanUrl) {
-        String[] pathSegments = buildScanUrl.getPath().split("/");
-        if (pathSegments.length <= 2 || !pathSegments[1].equals("s")) {
-            throw new IllegalArgumentException("Invalid Build Scan URL: " + buildScanUrl);
-        }
-        return pathSegments[2];
-    }
-
-    //TODO duplicated in NumberedBuildScan
-    private static URL toURL(String url) {
-        try {
-            return new URL(url);
-        } catch (MalformedURLException e) {
-            throw new IllegalArgumentException("Invalid Build Scan URL: " + url, e);
-        }
-    }
 }
diff --git a/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java b/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java
new file mode 100644
index 00000000..a97f9d85
--- /dev/null
+++ b/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java
@@ -0,0 +1,43 @@
+package com.gradle.enterprise.loader;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BuildScanUrlUtilsTest {
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "https://ge.example.com/s/7slcdesxr2xnw",
+            "https://ge.example.com/s/7slcdesxr2xnw/",
+            "https://ge.example.com/s/7slcdesxr2xnw/timeline",
+            "https://ge.example.com/s/7slcdesxr2xnw/console-log?page=1",
+            "https://ge.example.com/s/7slcdesxr2xnw/projects#:foo-service"
+    })
+    void validBuildScanUrlsAreCorrectlyParsed(String givenBuildScanUrl) throws URISyntaxException {
+        URL buildScanUrl = BuildScanUrlUtils.toBuildScanURL(new URI(givenBuildScanUrl));
+        assertAll(
+            () -> assertEquals(new URL("https://ge.example.com"), BuildScanUrlUtils.extractBaseUrl(buildScanUrl)),
+            () -> assertEquals("7slcdesxr2xnw", BuildScanUrlUtils.extractBuildScanId(buildScanUrl))
+        );
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "https://ge.example.com",
+            "https://ge.example.com/",
+            "https://ge.example.com/s",
+            "https://ge.example.com/s/",
+            "https://ge.example.com/S/",
+            "https://ge.example.com/S/7slcdesxr2xnw",
+    })
+    void invalidBuildScanUrlsThrowException(String givenBuildScanUrl) throws URISyntaxException {
+        URL buildScanUrl = BuildScanUrlUtils.toBuildScanURL(new URI(givenBuildScanUrl));
+        assertThrows(IllegalArgumentException.class, () -> BuildScanUrlUtils.extractBuildScanId(buildScanUrl));
+    }
+}
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTests.java b/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTest.java
similarity index 97%
rename from components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTests.java
rename to components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTest.java
index ecdb6766..6cba0bf7 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTests.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/cli/DurationFormatTest.java
@@ -7,7 +7,7 @@
 import static org.junit.jupiter.api.Assertions.assertAll;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class DurationFormatTests {
+public class DurationFormatTest {
 
     @Test
     void durationsAreFormattedCorrectly() {

From 4e6abc834e55c17ed7dc342f1fcc02f72f5b42a8 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 07:58:39 +0200
Subject: [PATCH 47/57] Simplify NumberedBuildScan

It no longer needs to parse and interpret the Build Scan URL.
---
 .../api/client/GradleEnterpriseApiClient.java | 11 ++-
 .../cli/FetchBuildScanDataCommand.java        | 12 ++--
 .../enterprise/model/NumberedBuildScan.java   | 67 +++----------------
 .../model/NumberedBuildScanTests.java         | 42 ------------
 4 files changed, 21 insertions(+), 111 deletions(-)
 delete mode 100644 components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/model/NumberedBuildScanTests.java

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 4ca44374..92a3f5f7 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -39,15 +39,14 @@ public GradleEnterpriseApiClient(CustomValueNames customValueNames, BuildScanDat
     }
 
     public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
-        int runNum = buildScan.runNum();
-        String buildScanId = buildScan.buildScanId();
-        BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.uri());
+        int runNum = buildScan.runNum;
+        BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.resource);
         if (buildToolType.equals(GRADLE)) {
-            return analyzeGradleBuild(runNum, buildScanDataLoader.loadDataForGradle(buildScan.uri()));
+            return analyzeGradleBuild(runNum, buildScanDataLoader.loadDataForGradle(buildScan.resource));
         } else if (buildToolType.equals(MAVEN)) {
-            return analyzeMavenBuild(runNum, buildScanDataLoader.loadDataForMaven(buildScan.uri()));
+            return analyzeMavenBuild(runNum, buildScanDataLoader.loadDataForMaven(buildScan.resource));
         } else {
-            throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.url(), buildToolType));
+            throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.resource, buildToolType));
         }
     }
 
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index 38168dd0..0e6f312e 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -91,7 +91,7 @@ private BuildScanData fetchBuildScanData(NumberedBuildScan buildScan, CustomValu
         logStartFetchingBuildScanData(buildScan);
         try {
             // TODO can we create one of these for everyone?
-            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(customValueNames, createBuildScanDataLoader(buildScan.uri(), licenseFile, logger));
+            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(customValueNames, createBuildScanDataLoader(buildScan.resource, licenseFile, logger));
             BuildScanData data = apiClient.fetchBuildScanData(buildScan);
 
             logFinishedFetchingBuildScanData(buildScan);
@@ -99,10 +99,10 @@ private BuildScanData fetchBuildScanData(NumberedBuildScan buildScan, CustomValu
         } catch (RuntimeException e) {
             logException(e);
             return new BuildScanData(
-                buildScan.runNum(),
+                buildScan.runNum,
                 "",
-                buildScan.buildScanId(),
-                buildScan.baseUrl(),
+                "",
+                null,
                 "",
                 "",
                 "",
@@ -149,13 +149,13 @@ private void logFinishedFetchingAllBuildScanData() {
 
     private void logStartFetchingBuildScanData(NumberedBuildScan buildScan) {
         if (!briefLogging) {
-            logger.info("Fetching Build Scan data for %s build", toOrdinal(buildScan.runNum()));
+            logger.info("Fetching Build Scan data for %s build", toOrdinal(buildScan.runNum));
         }
     }
 
     private void logFinishedFetchingBuildScanData(NumberedBuildScan buildScan) {
         if (!briefLogging) {
-            logger.info("Finished fetching Build Scan data for %s build", toOrdinal(buildScan.runNum()));
+            logger.info("Finished fetching Build Scan data for %s build", toOrdinal(buildScan.runNum));
         }
     }
 
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
index f22026e9..72519de6 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/NumberedBuildScan.java
@@ -10,14 +10,12 @@
 import static java.lang.Integer.parseInt;
 
 public class NumberedBuildScan {
-    private final int runNum;
-    private final URL baseUrl;
-    private final String buildScanId;
+    public final int runNum;
+    public final URI resource;
 
-    private NumberedBuildScan(int runNum, URL baseUrl, String buildScanId) {
+    private NumberedBuildScan(int runNum, URI resource) {
         this.runNum = runNum;
-        this.baseUrl = baseUrl;
-        this.buildScanId = buildScanId;
+        this.resource = resource;
     }
 
     public static List<NumberedBuildScan> parse(List<String> runNumsAndBuildScanUrls) {
@@ -27,65 +25,20 @@ public static List<NumberedBuildScan> parse(List<String> runNumsAndBuildScanUrls
     public static NumberedBuildScan parse(String runNumAndBuildScanUrl) {
         String[] parts = runNumAndBuildScanUrl.split(",");
         if (parts.length != 2) {
-            throw new IllegalArgumentException("Invalid numbered Build Scan URL: " + runNumAndBuildScanUrl);
+            throw new IllegalArgumentException("Invalid numbered Build Scan: " + runNumAndBuildScanUrl);
         }
 
         String runNum = parts[0];
-        URL buildScanUrl = toURL(parts[1]);
+        URI buildScanResource = toURI(parts[1]);
 
-        return new NumberedBuildScan(
-            parseInt(runNum),
-            extractBaseUrl(buildScanUrl),
-            extractBuildScanId(buildScanUrl)
-        );
+        return new NumberedBuildScan(parseInt(runNum), buildScanResource);
     }
 
-    public int runNum() {
-        return runNum;
-    }
-
-    public URL baseUrl() {
-        return baseUrl;
-    }
-
-    public String buildScanId() {
-        return buildScanId;
-    }
-
-    public URL url() {
-        try {
-            return new URL(baseUrl, "/s/" + buildScanId);
-        } catch (MalformedURLException e) {
-            throw new RuntimeException(e.getMessage(), e);
-        }
-    }
-
-    public URI uri() { // todo
+    private static URI toURI(String resource) {
         try {
-            return url().toURI();
+            return new URI(resource);
         } catch (URISyntaxException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static URL extractBaseUrl(URL buildScanUrl) {
-        String port = (buildScanUrl.getPort() != -1) ? ":" + buildScanUrl.getPort() : "";
-        return toURL(buildScanUrl.getProtocol() + "://" + buildScanUrl.getHost() + port);
-    }
-
-    private static String extractBuildScanId(URL buildScanUrl) {
-        String[] pathSegments = buildScanUrl.getPath().split("/");
-        if (pathSegments.length <= 2 || !pathSegments[1].equals("s")) {
-            throw new IllegalArgumentException("Invalid Build Scan URL: " + buildScanUrl);
-        }
-        return pathSegments[2];
-    }
-
-    private static URL toURL(String url) {
-        try {
-            return new URL(url);
-        } catch (MalformedURLException e) {
-            throw new IllegalArgumentException("Invalid Build Scan URL: " + url, e);
+            throw new IllegalArgumentException("Invalid Build Scan resource: " + resource, e);
         }
     }
 }
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/model/NumberedBuildScanTests.java b/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/model/NumberedBuildScanTests.java
deleted file mode 100644
index fb5404d0..00000000
--- a/components/fetch-build-scan-data-cmdline-tool/src/test/java/com/gradle/enterprise/model/NumberedBuildScanTests.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.gradle.enterprise.model;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import java.net.URL;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class NumberedBuildScanTests {
-
-    @ParameterizedTest
-    @ValueSource(strings = {
-            "https://ge.example.com/s/7slcdesxr2xnw",
-            "https://ge.example.com/s/7slcdesxr2xnw/",
-            "https://ge.example.com/s/7slcdesxr2xnw/timeline",
-            "https://ge.example.com/s/7slcdesxr2xnw/console-log?page=1",
-            "https://ge.example.com/s/7slcdesxr2xnw/projects#:foo-service"
-    })
-    void validBuildScanUrlsAreCorrectlyParsed(String buildScanUrl) {
-        final NumberedBuildScan numberedBuildScan = NumberedBuildScan.parse("0," + buildScanUrl);
-        assertAll(
-                () -> assertEquals(new URL("https://ge.example.com"), numberedBuildScan.baseUrl()),
-                () -> assertEquals("7slcdesxr2xnw", numberedBuildScan.buildScanId())
-        );
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = {
-            "https://ge.example.com",
-            "https://ge.example.com/",
-            "https://ge.example.com/s",
-            "https://ge.example.com/s/",
-            "https://ge.example.com/S/",
-            "https://ge.example.com/S/7slcdesxr2xnw",
-    })
-    void invalidBuildScanUrlsThrowException(String buildScanUrl) {
-        assertThrows(IllegalArgumentException.class, () -> NumberedBuildScan.parse("0," + buildScanUrl));
-    }
-}

From 5155076414823b178d3f9aa257b5ce0b1e8fef4e Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 08:02:11 +0200
Subject: [PATCH 48/57] Move online data loader classes to an loader.online
 package

---
 .../loader/{ => online}/AuthenticationConfigurator.java     | 3 ++-
 .../enterprise/loader/{ => online}/BuildScanUrlUtils.java   | 2 +-
 .../loader/{ => online}/FailedRequestException.java         | 2 +-
 .../loader/{ => online}/GradleEnterpriseApiClient.java      | 3 ++-
 .../loader/{ => online}/OnlineBuildScanDataLoader.java      | 6 ++++--
 .../loader/{ => online}/BuildScanUrlUtilsTest.java          | 3 ++-
 .../enterprise/api/client/GradleEnterpriseApiClient.java    | 4 ----
 .../gradle/enterprise/cli/BuildScanDataLoaderFactory.java   | 2 +-
 .../gradle/enterprise/cli/FetchBuildScanDataCommand.java    | 2 +-
 9 files changed, 14 insertions(+), 13 deletions(-)
 rename components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/{ => online}/AuthenticationConfigurator.java (98%)
 rename components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/{ => online}/BuildScanUrlUtils.java (96%)
 rename components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/{ => online}/FailedRequestException.java (96%)
 rename components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/{ => online}/GradleEnterpriseApiClient.java (98%)
 rename components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/{ => online}/OnlineBuildScanDataLoader.java (92%)
 rename components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/{ => online}/BuildScanUrlUtilsTest.java (94%)

diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/AuthenticationConfigurator.java
similarity index 98%
rename from components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java
rename to components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/AuthenticationConfigurator.java
index 35845116..b241384a 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/AuthenticationConfigurator.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/AuthenticationConfigurator.java
@@ -1,7 +1,8 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
 import com.google.common.base.Strings;
 import com.gradle.enterprise.api.client.ApiClient;
+import com.gradle.enterprise.loader.Logger;
 
 import java.io.BufferedReader;
 import java.io.IOException;
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/BuildScanUrlUtils.java
similarity index 96%
rename from components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java
rename to components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/BuildScanUrlUtils.java
index 0525f94d..bdeff882 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/BuildScanUrlUtils.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/BuildScanUrlUtils.java
@@ -1,4 +1,4 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
 import java.net.MalformedURLException;
 import java.net.URI;
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/FailedRequestException.java
similarity index 96%
rename from components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java
rename to components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/FailedRequestException.java
index 8d1c4bac..b17df284 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/FailedRequestException.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/FailedRequestException.java
@@ -1,4 +1,4 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
 import com.gradle.enterprise.api.client.ApiException;
 
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/GradleEnterpriseApiClient.java
similarity index 98%
rename from components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
rename to components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/GradleEnterpriseApiClient.java
index e0a4e437..97db23cd 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/GradleEnterpriseApiClient.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/GradleEnterpriseApiClient.java
@@ -1,10 +1,11 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
 import com.gradle.enterprise.api.GradleEnterpriseApi;
 import com.gradle.enterprise.api.client.ApiClient;
 import com.gradle.enterprise.api.client.ApiException;
 import com.gradle.enterprise.api.model.*;
 import com.gradle.enterprise.loader.BuildScanDataLoader.BuildScanData;
+import com.gradle.enterprise.loader.Logger;
 import okhttp3.Credentials;
 import okhttp3.OkHttpClient;
 import okhttp3.tls.HandshakeCertificates;
diff --git a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/OnlineBuildScanDataLoader.java
similarity index 92%
rename from components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
rename to components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/OnlineBuildScanDataLoader.java
index daeec283..1af7f367 100644
--- a/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/OnlineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-online/src/main/java/com/gradle/enterprise/loader/online/OnlineBuildScanDataLoader.java
@@ -1,17 +1,19 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
 import com.gradle.enterprise.api.client.ApiException;
 import com.gradle.enterprise.api.model.GradleAttributes;
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+import com.gradle.enterprise.loader.BuildScanDataLoader;
+import com.gradle.enterprise.loader.Logger;
 
 import java.net.URI;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
 
-import static com.gradle.enterprise.loader.BuildScanUrlUtils.*;
+import static com.gradle.enterprise.loader.online.BuildScanUrlUtils.*;
 
 public final class OnlineBuildScanDataLoader implements BuildScanDataLoader {
 
diff --git a/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java b/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/online/BuildScanUrlUtilsTest.java
similarity index 94%
rename from components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java
rename to components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/online/BuildScanUrlUtilsTest.java
index a97f9d85..3cdb23eb 100644
--- a/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/BuildScanUrlUtilsTest.java
+++ b/components/build-scan-data-loader-online/src/test/java/com/gradle/enterprise/loader/online/BuildScanUrlUtilsTest.java
@@ -1,5 +1,6 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.online;
 
+import com.gradle.enterprise.loader.online.BuildScanUrlUtils;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
index 92a3f5f7..51627ef6 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
@@ -2,9 +2,6 @@
 
 import com.gradle.enterprise.api.model.*;
 import com.gradle.enterprise.loader.BuildScanDataLoader;
-import com.gradle.enterprise.loader.Logger;
-import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
-import com.gradle.enterprise.loader.OnlineBuildScanDataLoader;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
@@ -13,7 +10,6 @@
 import java.math.BigDecimal;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.nio.file.Path;
 import java.time.Duration;
 import java.util.AbstractMap;
 import java.util.Arrays;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
index 88d7ab5e..7654140d 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
@@ -3,7 +3,7 @@
 import com.gradle.enterprise.loader.BuildScanDataLoader;
 import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
-import com.gradle.enterprise.loader.OnlineBuildScanDataLoader;
+import com.gradle.enterprise.loader.online.OnlineBuildScanDataLoader;
 
 import java.net.URI;
 import java.nio.file.Path;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index 0e6f312e..669f7a65 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -1,7 +1,7 @@
 package com.gradle.enterprise.cli;
 
 import com.gradle.enterprise.api.client.GradleEnterpriseApiClient;
-import com.gradle.enterprise.loader.FailedRequestException;
+import com.gradle.enterprise.loader.online.FailedRequestException;
 import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;

From 39a83b37fc3c1a8611724ed1b6ec2a791f7a6154 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 08:02:42 +0200
Subject: [PATCH 49/57] Move offline Build Scan data loader classes to a
 loader.offline package

---
 .../loader/{ => offline}/OfflineBuildScanDataLoader.java       | 3 ++-
 .../loader/{ => offline}/ReflectiveBuildScanDumpReader.java    | 2 +-
 .../com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java  | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)
 rename components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/{ => offline}/OfflineBuildScanDataLoader.java (92%)
 rename components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/{ => offline}/ReflectiveBuildScanDumpReader.java (99%)

diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/OfflineBuildScanDataLoader.java
similarity index 92%
rename from components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
rename to components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/OfflineBuildScanDataLoader.java
index fb159ded..8e12a18e 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/OfflineBuildScanDataLoader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/OfflineBuildScanDataLoader.java
@@ -1,9 +1,10 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.offline;
 
 import com.gradle.enterprise.api.model.GradleAttributes;
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenAttributes;
 import com.gradle.enterprise.api.model.MavenBuildCachePerformance;
+import com.gradle.enterprise.loader.BuildScanDataLoader;
 
 import java.net.URI;
 import java.nio.file.Path;
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
similarity index 99%
rename from components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
rename to components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
index 946adaa9..46e63d7a 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
@@ -1,4 +1,4 @@
-package com.gradle.enterprise.loader;
+package com.gradle.enterprise.loader.offline;
 
 import com.gradle.enterprise.api.model.GradleAttributes;
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
index 7654140d..e3da7096 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataLoaderFactory.java
@@ -2,7 +2,7 @@
 
 import com.gradle.enterprise.loader.BuildScanDataLoader;
 import com.gradle.enterprise.loader.Logger;
-import com.gradle.enterprise.loader.OfflineBuildScanDataLoader;
+import com.gradle.enterprise.loader.offline.OfflineBuildScanDataLoader;
 import com.gradle.enterprise.loader.online.OnlineBuildScanDataLoader;
 
 import java.net.URI;

From cda46dbd0acb9e2a0d1c0da0c36f4467bb142328 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 08:05:02 +0200
Subject: [PATCH 50/57] Rename GradleEnterpriseApiClient to
 BuildScanDataAnalyzer

We had two GradleEnterpriseApiClient classes that did very different things.
Additionally, BuildScanDataAnalyzer only analyzes the data fetched by the
loaders, it doesn't interact with the API directly itself.
---
 ...seApiClient.java => BuildScanDataAnalyzer.java} | 14 +++++++-------
 .../enterprise/cli/FetchBuildScanDataCommand.java  |  8 ++++----
 2 files changed, 11 insertions(+), 11 deletions(-)
 rename components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/{GradleEnterpriseApiClient.java => BuildScanDataAnalyzer.java} (95%)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java
similarity index 95%
rename from components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
rename to components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java
index 51627ef6..4ddb85c7 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/GradleEnterpriseApiClient.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java
@@ -24,17 +24,17 @@
 import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType;
 import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType.*;
 
-public final class GradleEnterpriseApiClient {
+public final class BuildScanDataAnalyzer {
 
     private final CustomValueNames customValueNames;
     private final BuildScanDataLoader buildScanDataLoader;
 
-    public GradleEnterpriseApiClient(CustomValueNames customValueNames, BuildScanDataLoader buildScanDataLoader) {
+    public BuildScanDataAnalyzer(CustomValueNames customValueNames, BuildScanDataLoader buildScanDataLoader) {
         this.customValueNames = customValueNames;
         this.buildScanDataLoader = buildScanDataLoader;
     }
 
-    public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
+    public BuildScanData analyzeBuildScanData(NumberedBuildScan buildScan) {
         int runNum = buildScan.runNum;
         BuildToolType buildToolType = buildScanDataLoader.determineBuildToolType(buildScan.resource);
         if (buildToolType.equals(GRADLE)) {
@@ -42,7 +42,7 @@ public BuildScanData fetchBuildScanData(NumberedBuildScan buildScan) {
         } else if (buildToolType.equals(MAVEN)) {
             return analyzeMavenBuild(runNum, buildScanDataLoader.loadDataForMaven(buildScan.resource));
         } else {
-            throw new RuntimeException(String.format("Build scan %s was generated by an unknown build agent: %s.", buildScan.resource, buildToolType));
+            throw new RuntimeException(String.format("Build Scan %s was generated by an unknown build agent: %s.", buildScan.resource, buildToolType));
         }
     }
 
@@ -145,11 +145,11 @@ private static URL remoteBuildCacheUrlFrom(MavenBuildCachePerformance buildCache
 
     private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(GradleBuildCachePerformance buildCachePerformance) {
         Map<String, List<GradleBuildCachePerformanceTaskExecutionEntry>> tasksByOutcome = buildCachePerformance.getTaskExecution().stream()
-                .collect(Collectors.groupingBy(GradleEnterpriseApiClient::avoidanceOutcome));
+                .collect(Collectors.groupingBy(BuildScanDataAnalyzer::avoidanceOutcome));
 
         Map<String, TaskExecutionSummary> summariesByOutcome = tasksByOutcome.entrySet()
                 .stream()
-                .map(GradleEnterpriseApiClient::summarizeForGradle)
+                .map(BuildScanDataAnalyzer::summarizeForGradle)
                 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
         Arrays.stream(GradleBuildCachePerformanceTaskExecutionEntry.AvoidanceOutcomeEnum.values())
@@ -175,7 +175,7 @@ private static Map<String, TaskExecutionSummary> summarizeTaskExecutions(MavenBu
 
         Map<String, TaskExecutionSummary> summariesByOutcome = tasksByOutcome.entrySet()
                 .stream()
-                .map(GradleEnterpriseApiClient::summarizeForMaven)
+                .map(BuildScanDataAnalyzer::summarizeForMaven)
                 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
         Arrays.stream(MavenBuildCachePerformanceGoalExecutionEntry.AvoidanceOutcomeEnum.values())
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index 669f7a65..bf933333 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -1,6 +1,6 @@
 package com.gradle.enterprise.cli;
 
-import com.gradle.enterprise.api.client.GradleEnterpriseApiClient;
+import com.gradle.enterprise.api.client.BuildScanDataAnalyzer;
 import com.gradle.enterprise.loader.online.FailedRequestException;
 import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;
@@ -90,9 +90,9 @@ private List<BuildScanData> fetchBuildScanData(List<NumberedBuildScan> buildScan
     private BuildScanData fetchBuildScanData(NumberedBuildScan buildScan, CustomValueNames customValueNames) {
         logStartFetchingBuildScanData(buildScan);
         try {
-            // TODO can we create one of these for everyone?
-            GradleEnterpriseApiClient apiClient = new GradleEnterpriseApiClient(customValueNames, createBuildScanDataLoader(buildScan.resource, licenseFile, logger));
-            BuildScanData data = apiClient.fetchBuildScanData(buildScan);
+            // TODO can we create one analyzer for all build scans?
+            BuildScanDataAnalyzer analyzer = new BuildScanDataAnalyzer(customValueNames, createBuildScanDataLoader(buildScan.resource, licenseFile, logger));
+            BuildScanData data = analyzer.analyzeBuildScanData(buildScan);
 
             logFinishedFetchingBuildScanData(buildScan);
             return data;

From 148faf32c3abb97ccf6d3bd343c88ace11d82e34 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 08:06:42 +0200
Subject: [PATCH 51/57] Move BuildScanDataAnalyzer to the cli package

It didn't really belong in the api.client package anymore.
---
 .../enterprise/{api/client => cli}/BuildScanDataAnalyzer.java   | 2 +-
 .../com/gradle/enterprise/cli/FetchBuildScanDataCommand.java    | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)
 rename components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/{api/client => cli}/BuildScanDataAnalyzer.java (99%)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataAnalyzer.java
similarity index 99%
rename from components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java
rename to components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataAnalyzer.java
index 4ddb85c7..dd46539a 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/api/client/BuildScanDataAnalyzer.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/BuildScanDataAnalyzer.java
@@ -1,4 +1,4 @@
-package com.gradle.enterprise.api.client;
+package com.gradle.enterprise.cli;
 
 import com.gradle.enterprise.api.model.*;
 import com.gradle.enterprise.loader.BuildScanDataLoader;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index bf933333..6ccce407 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -1,6 +1,5 @@
 package com.gradle.enterprise.cli;
 
-import com.gradle.enterprise.api.client.BuildScanDataAnalyzer;
 import com.gradle.enterprise.loader.online.FailedRequestException;
 import com.gradle.enterprise.loader.Logger;
 import com.gradle.enterprise.model.BuildScanData;

From 64e27bc24d4a9e32f6689533edb177a6f62795e0 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 13:58:00 -0400
Subject: [PATCH 52/57] Update invoke_java to allow setting the classpath

This makes invoke_java even closer to the Gradle Application Plugin's generated
Java launch script.
---
 components/scripts/lib/build-scan-online.sh |  5 +++--
 components/scripts/lib/java.sh              | 11 ++++++++---
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/components/scripts/lib/build-scan-online.sh b/components/scripts/lib/build-scan-online.sh
index 39d43aac..461f6988 100644
--- a/components/scripts/lib/build-scan-online.sh
+++ b/components/scripts/lib/build-scan-online.sh
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 
-readonly FETCH_BUILD_SCAN_DATA_JAR="${LIB_DIR}/build-scan-clients/fetch-build-scan-data-cmdline-tool-${SCRIPT_VERSION}-all.jar"
+readonly FETCH_BUILD_SCAN_DATA_MAIN_CLASS="com.gradle.enterprise.Main"
+readonly BUILD_SCAN_CLIENTS="${LIB_DIR}/build-scan-clients"
 
 # This is a helper function for the common pattern of reading Build Scan metadata
 # from the build-scans.csv file, then retrieving build metrics using the Gradle
@@ -105,5 +106,5 @@ fetch_build_scan_data() {
     args+=( "${run_num},${build_scan_urls[run_num]}" )
   done
 
-  invoke_java "${FETCH_BUILD_SCAN_DATA_JAR}" "${args[@]}"
+  APP_OPTS="-Dpicocli.ansi=true" invoke_java "${BUILD_SCAN_CLIENTS}/*" "${FETCH_BUILD_SCAN_DATA_MAIN_CLASS}" "${args[@]}"
 }
diff --git a/components/scripts/lib/java.sh b/components/scripts/lib/java.sh
index e3289b84..e2fe9908 100644
--- a/components/scripts/lib/java.sh
+++ b/components/scripts/lib/java.sh
@@ -8,7 +8,9 @@
 #
 # shellcheck disable=SC2128,SC2178
 invoke_java() {
-  local classpath="$1"
+  local CLASSPATH="$1"
+  shift
+  local mainClassName="$1"
   shift
 
   # OS specific support (must be 'true' or 'false').
@@ -39,7 +41,7 @@ location of your Java installation."
     fi
   else
     JAVACMD=java
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
@@ -111,7 +113,10 @@ location of your Java installation."
   #     double quotes to make sure that they get re-expanded; and
   #   * put everything else in single quotes, so that it's not re-expanded.
 
-  set -- -Dpicocli.ansi=true -jar "$classpath" "$@"
+  set -- \
+    -classpath "$CLASSPATH" \
+    "${mainClassName}" \
+    "$@"
 
   # Stop when "xargs" is not available.
   if ! command -v xargs >/dev/null 2>&1; then

From 0d866819258508fa3e14df0040dfe0164c4b6681 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 14:30:05 -0400
Subject: [PATCH 53/57] Update Google GSON to 2.10.1

---
 components/build-scan-data-loader-api/build.gradle.kts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/components/build-scan-data-loader-api/build.gradle.kts b/components/build-scan-data-loader-api/build.gradle.kts
index 8ba0d4e8..274151a3 100644
--- a/components/build-scan-data-loader-api/build.gradle.kts
+++ b/components/build-scan-data-loader-api/build.gradle.kts
@@ -40,6 +40,7 @@ dependencies {
 
     implementation("io.swagger:swagger-annotations:1.6.10")
     implementation("io.gsonfire:gson-fire:1.8.5")
+    implementation("com.google.code.gson:gson:2.10.1")
     implementation("javax.ws.rs:jsr311-api:1.1.1")
     implementation("javax.ws.rs:javax.ws.rs-api:2.1.1")
 

From 518cc149ae2b9f95395ecc7ae97e236af61c95cd Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 14:35:34 -0400
Subject: [PATCH 54/57] Explicitly ensure the
 fetch-build-scan-data-cmdline-tool jar takes priority over the
 build-scan-dump-reader jar

This avoids tricky dependency conflicts that prevent the tool from working properly.
---
 components/scripts/lib/build-scan-online.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/components/scripts/lib/build-scan-online.sh b/components/scripts/lib/build-scan-online.sh
index 461f6988..907527c3 100644
--- a/components/scripts/lib/build-scan-online.sh
+++ b/components/scripts/lib/build-scan-online.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 
+readonly FETCH_BUILD_SCAN_DATA_JAR="${LIB_DIR}/build-scan-clients/fetch-build-scan-data-cmdline-tool-${SCRIPT_VERSION}-all.jar"
 readonly FETCH_BUILD_SCAN_DATA_MAIN_CLASS="com.gradle.enterprise.Main"
-readonly BUILD_SCAN_CLIENTS="${LIB_DIR}/build-scan-clients"
 
 # This is a helper function for the common pattern of reading Build Scan metadata
 # from the build-scans.csv file, then retrieving build metrics using the Gradle
@@ -106,5 +106,5 @@ fetch_build_scan_data() {
     args+=( "${run_num},${build_scan_urls[run_num]}" )
   done
 
-  APP_OPTS="-Dpicocli.ansi=true" invoke_java "${BUILD_SCAN_CLIENTS}/*" "${FETCH_BUILD_SCAN_DATA_MAIN_CLASS}" "${args[@]}"
+  APP_OPTS="-Dpicocli.ansi=true" invoke_java "${FETCH_BUILD_SCAN_DATA_JAR}:${BUILD_SCAN_DUMP_READER_JAR}" "${FETCH_BUILD_SCAN_DATA_MAIN_CLASS}" "${args[@]}"
 }

From fa4454630a424b723762dc613beda05cba363fae Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Sat, 13 May 2023 14:44:49 -0400
Subject: [PATCH 55/57] Better handle a null gradleEnterpriseURL

...which can happen if fetching data for a Build Scan fails.
---
 .../enterprise/cli/FetchBuildScanDataCommand.java    |  2 +-
 .../com/gradle/enterprise/model/BuildScanData.java   | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
index 6ccce407..a87cb4c5 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/cli/FetchBuildScanDataCommand.java
@@ -1,7 +1,7 @@
 package com.gradle.enterprise.cli;
 
-import com.gradle.enterprise.loader.online.FailedRequestException;
 import com.gradle.enterprise.loader.Logger;
+import com.gradle.enterprise.loader.online.FailedRequestException;
 import com.gradle.enterprise.model.BuildScanData;
 import com.gradle.enterprise.model.CustomValueNames;
 import com.gradle.enterprise.model.NumberedBuildScan;
diff --git a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/BuildScanData.java b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/BuildScanData.java
index ead416dd..0bbbe893 100644
--- a/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/BuildScanData.java
+++ b/components/fetch-build-scan-data-cmdline-tool/src/main/java/com/gradle/enterprise/model/BuildScanData.java
@@ -68,10 +68,14 @@ public String getBuildScanId() {
     }
 
     public URL getBuildScanUrl() {
-        try {
-            return new URL(gradleEnterpriseServerUrl, "/s/" + buildScanId);
-        } catch (MalformedURLException e) {
-            throw new RuntimeException(e.getMessage(), e);
+        if (gradleEnterpriseServerUrl == null) {
+            return null;
+        } else {
+            try {
+                return new URL(gradleEnterpriseServerUrl, "/s/" + buildScanId);
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            }
         }
     }
 

From bb926ba23338d193180d0c25b5ab82b7dc7f242e Mon Sep 17 00:00:00 2001
From: Sorin Florea <sflorea@gradle.com>
Date: Mon, 15 May 2023 12:26:53 +0200
Subject: [PATCH 56/57] Parse JSON in offline loader

---
 build.gradle.kts                              |  2 +-
 .../build.gradle.kts                          |  4 +++-
 .../ReflectiveBuildScanDumpReader.java        | 22 ++++++++++++-------
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index 91c03c6a..115cbf70 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -309,4 +309,4 @@ fun releaseVersion(): Provider<String> {
 fun releaseNotes(): Provider<String> {
     val releaseNotesFile = layout.projectDirectory.file("release/changes.md")
     return providers.fileContents(releaseNotesFile).asText.map { it.trim() }
-}
\ No newline at end of file
+}
diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index d7783ef8..c726242a 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -7,7 +7,9 @@ repositories {
 }
 
 dependencies {
-    api(project(":build-scan-data-loader-api"))
+    implementation(project(":build-scan-data-loader-api"))
+    implementation("com.google.code.gson:gson:2.10.1")
+    implementation("io.gsonfire:gson-fire:1.8.5")
 }
 
 java {
diff --git a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
index 46e63d7a..cf60a029 100644
--- a/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
+++ b/components/build-scan-data-loader-offline/src/main/java/com/gradle/enterprise/loader/offline/ReflectiveBuildScanDumpReader.java
@@ -1,5 +1,7 @@
 package com.gradle.enterprise.loader.offline;
 
+import com.google.gson.reflect.TypeToken;
+import com.gradle.enterprise.api.client.JSON;
 import com.gradle.enterprise.api.model.GradleAttributes;
 import com.gradle.enterprise.api.model.GradleBuildCachePerformance;
 import com.gradle.enterprise.api.model.MavenAttributes;
@@ -12,12 +14,14 @@
 import java.nio.file.Path;
 import java.util.Optional;
 
-import static com.gradle.enterprise.loader.BuildScanDataLoader.*;
+import static com.gradle.enterprise.loader.BuildScanDataLoader.BuildToolType;
 
 final class ReflectiveBuildScanDumpReader {
-
     private final Object buildScanDumpReader;
 
+    // We need to instantiate the class so that the gson field is initialized.
+    private final static JSON json = new JSON();
+
     private ReflectiveBuildScanDumpReader(Object buildScanDumpReader) {
         this.buildScanDumpReader = buildScanDumpReader;
     }
@@ -55,9 +59,10 @@ BuildScanData<GradleAttributes, GradleBuildCachePerformance> readGradleBuildScan
         try {
             Method extractGradleBuildScanDump = buildScanDumpReader.getClass().getMethod("readGradleBuildScanDump", Path.class);
             Object gradleBuild = extractGradleBuildScanDump.invoke(buildScanDumpReader, scanDump);
-
-            GradleAttributes attributes = (GradleAttributes) gradleBuild.getClass().getField("attributes").get(gradleBuild);
-            GradleBuildCachePerformance buildCachePerformance = (GradleBuildCachePerformance) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild);
+            GradleAttributes attributes = JSON.deserialize((String) gradleBuild.getClass().getField("attributes").get(gradleBuild), new TypeToken<GradleAttributes>() {
+            }.getType());
+            GradleBuildCachePerformance buildCachePerformance = JSON.deserialize((String) gradleBuild.getClass().getField("buildCachePerformance").get(gradleBuild), new TypeToken<GradleBuildCachePerformance>() {
+            }.getType());
 
             return new BuildScanData<>(Optional.empty(), attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {
@@ -73,9 +78,10 @@ BuildScanData<MavenAttributes, MavenBuildCachePerformance> readMavenBuildScanDum
         try {
             Method extractMavenBuildScanDump = buildScanDumpReader.getClass().getMethod("readMavenBuildScanDump", Path.class);
             Object mavenBuild = extractMavenBuildScanDump.invoke(buildScanDumpReader, scanDump);
-
-            MavenAttributes attributes = (MavenAttributes) mavenBuild.getClass().getField("attributes").get(mavenBuild);
-            MavenBuildCachePerformance buildCachePerformance = (MavenBuildCachePerformance) mavenBuild.getClass().getField("buildCachePerformance").get(mavenBuild);
+            MavenAttributes attributes = JSON.deserialize((String) mavenBuild.getClass().getField("attributes").get(mavenBuild), new TypeToken<MavenAttributes>() {
+            }.getType());
+            MavenBuildCachePerformance buildCachePerformance = JSON.deserialize((String) mavenBuild.getClass().getField("buildCachePerformance").get(mavenBuild), new TypeToken<MavenBuildCachePerformance>() {
+            }.getType());
 
             return new BuildScanData<>(Optional.empty(), attributes, buildCachePerformance);
         } catch (InvocationTargetException e) {

From 8254e9ecf90a16e1d114349e2cc7e876cdca42a0 Mon Sep 17 00:00:00 2001
From: Jim Hurne <jhurne@gradle.com>
Date: Mon, 15 May 2023 15:38:04 -0400
Subject: [PATCH 57/57] Mark build-scan-data-loader-api as an api dependency

...so that the downstream component can see and access the API provided by the api module.
---
 components/build-scan-data-loader-offline/build.gradle.kts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/components/build-scan-data-loader-offline/build.gradle.kts b/components/build-scan-data-loader-offline/build.gradle.kts
index c726242a..78178e76 100644
--- a/components/build-scan-data-loader-offline/build.gradle.kts
+++ b/components/build-scan-data-loader-offline/build.gradle.kts
@@ -7,7 +7,8 @@ repositories {
 }
 
 dependencies {
-    implementation(project(":build-scan-data-loader-api"))
+    api(project(":build-scan-data-loader-api"))
+
     implementation("com.google.code.gson:gson:2.10.1")
     implementation("io.gsonfire:gson-fire:1.8.5")
 }
