How do you accept the Build Scan terms of service so that scans publish non-interactively (e.g., on CI)?
answer
- CI has no TTY → prompt unanswered → no scan
- termsOfUseAgree = "yes"
- termsOfUseUrl
- -Dscan.terms-of-service.agree=yes
- governance / self-hosted Develocity
basics
~20 sOn a developer machine --scan prompts once and stores acceptance locally. On CI there is no prompt, so you pre-accept in config by setting termsOfUseUrl and termsOfUseAgree = "yes" in the Develocity buildScan block, or pass them as system properties.
solid answer
~40 sPublishing to the public scan server requires agreeing to its terms of service. Interactively, the **first** `--scan` run prints the terms and asks `Do you accept...? [yes, no]`; your `yes` is remembered per-machine. **CI has no TTY**, so an unanswered prompt means the scan silently won't publish. You pre-accept in configuration. With the Develocity plugin in `settings.gradle.kts`: ```kotlin develocity { buildScan { termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use" termsOfUseAgree = "yes" } } ``` Alternatively pass `-Dscan.terms-of-service.url=...` and `-Dscan.terms-of-service.agree=yes` as system properties on the command line. Pre-acceptance is a legal/governance decision: you are agreeing on behalf of everyone whose builds publish, so teams often gate it behind a Develocity server they control rather than the public server.
code
kotlin · 8 lines// settings.gradle.kts
develocity {
buildScan {
termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use"
termsOfUseAgree = "yes" // pre-accept — no interactive prompt
publishing.onlyIf { System.getenv("CI") != null }
}
}go deeper
Know that the first local --scan asks you to accept terms once.
Explain why CI needs termsOfUseAgree/system-property pre-acceptance and that the prompt can't be answered headlessly.
Add publish-on-CI-only or publish-on-failure policies and tie acceptance to a chosen server (public vs. Develocity).
Treat acceptance as a data-governance decision: who agrees on the org's behalf, what metadata leaves the network, and the self-hosting alternative.
## The problem The **public** Build Scan server (`scans.gradle.com`) is a hosted service with a **terms of service** you must accept before data leaves your machine. Locally this is a one-time interactive prompt: ``` The Gradle Terms of Use have not been agreed to yet. ... Do you accept these terms? [yes, no] ``` Your answer is persisted in a per-user location, so subsequent `--scan` runs publish silently. The friction appears in **non-interactive environments** — CI runners, scripts, Docker builds — which have **no stdin/TTY**. There the prompt cannot be answered, so the build proceeds but **the scan is not published** (often a confusing "why is there no scan?" moment). ## Pre-accepting in configuration The durable fix is to record acceptance in the build itself via the Develocity plugin in **`settings.gradle.kts`**: ```kotlin plugins { id("com.gradle.develocity") version "3.x" } develocity { buildScan { termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use" termsOfUseAgree = "yes" // optional: only publish from CI, only on failure, etc. publishing.onlyIf { System.getenv("CI") != null } } } ``` Setting `termsOfUseAgree = "yes"` together with the URL tells Gradle the terms are accepted programmatically, so no prompt is needed anywhere — local or CI. ## Via system properties If you can't (or don't want to) edit the build, supply the same acceptance on the command line: ```bash ./gradlew build --scan \ -Dscan.terms-of-service.url=https://gradle.com/help/legal-terms-of-use \ -Dscan.terms-of-service.agree=yes ``` ## Governance angle Pre-accepting means **someone is agreeing on behalf of the whole organization**, and build data (dependencies, environment, sometimes paths) is uploaded to a third-party host. Mature teams either (a) restrict public-scan publishing, or (b) run a **self-hosted Develocity** server where they own the data and the terms question is internal. The terms acceptance config is identical; you just point `server = "https://develocity.mycompany.com"` at your instance. ## Key distinction Accepting terms ≠ enabling publishing. You still need the `--scan` flag or a `publishing.onlyIf { ... }` policy for a scan to actually be produced. Terms acceptance just removes the interactive gate.
- Why does a CI build silently fail to produce a scan even when `--scan` is passed?Because the terms-of-service prompt has no TTY to answer it. Gradle can't get a `yes`, so it skips publishing without failing the build. Pre-accepting via `termsOfUseAgree`/system properties fixes it.
- What's the governance concern with pre-accepting public scan terms?You agree on behalf of the whole org and ship potentially sensitive build metadata to a third-party host. Many teams instead run self-hosted Develocity so the data and terms stay internal.
saying these in an interview costs you the question
- Assuming `--scan` always publishes on CI — without pre-accepted terms it silently does not.
- Confusing terms acceptance with enabling publishing; you still need the flag or an `onlyIf` policy.