Skip to content

feat(auto-install): Fail the build on OpenTelemetry version downgrades#1350

Merged
adinauer merged 18 commits into
mainfrom
side-quest/sagp-otel-version-check
Jul 14, 2026
Merged

feat(auto-install): Fail the build on OpenTelemetry version downgrades#1350
adinauer merged 18 commits into
mainfrom
side-quest/sagp-otel-version-check

Conversation

@adinauer

@adinauer adinauer commented Jul 2, 2026

Copy link
Copy Markdown
Member

Adds a JVM-only verifySentryOpenTelemetryVersions Gradle task that fails the build when the OpenTelemetry versions resolved on the runtime classpath are downgraded below what Sentry's sentry-opentelemetry-* artifacts require.

Why

Sentry's OpenTelemetry artifacts are built against a specific set of OpenTelemetry versions. When another dependency management mechanism — most commonly Spring Boot's io.spring.dependency-management — forces OpenTelemetry below those versions (which happens silently, without the user declaring any OTel version), running against the mismatched versions throws ClassNotFoundException / NoSuchMethodError at runtime. This surfaces the problem at build time with actionable guidance instead.

How it works

  • Walks the resolved runtimeClasspath graph and, for every OpenTelemetry module a sentry-opentelemetry-* artifact depends on, compares the requested vs. resolved version. Gradle preserves the originally-requested version on each edge even when a resolution rule (e.g. io.spring.dependency-management) forces it lower, so the downgrade is detectable.
  • The failure message adapts to the setup: it suggests importing the Sentry OpenTelemetry BOM through io.spring.dependency-management's imports { mavenBom(...) } when that plugin is applied (a platform() constraint loses to it), otherwise a plain platform(...) dependency.
  • Gated by a cheap declared-dependency check so it's skipped (no runtime classpath resolution) for projects that don't use Sentry OpenTelemetry.
  • Opt out via sentry.autoInstallation.verifyOpenTelemetryVersions = false (default true).

Context

Stacked on #1349 (base branch), which adds sentry-opentelemetry-bom awareness to auto-install.

This replaces an earlier approach that auto-imported the BOM: that only works with Gradle-native BOM support and is silently overridden by io.spring.dependency-management, so detecting-and-failing is the more honest behavior.

Open items from SDK-team review

  • Docs URL in the failure message is a placeholder (.../platforms/java/opentelemetry/troubleshooting/) and must resolve to a live page before release.
  • Default-on behavior is a product call: defaulting a build-breaking check to true will surprise existing Spring Boot users on upgrade. Either keep default-on with a clearly-flagged behavioral-change changelog entry, or ship opt-in first and flip later based on telemetry.

adinauer and others added 4 commits July 1, 2026 16:27
Detect Sentry BOM dependencies separately from concrete Sentry SDK dependencies so auto-install can use the BOM-selected SDK version without treating a BOM as the installed SDK.

This keeps integration installs aligned with sentry-bom and sentry-opentelemetry-bom declarations while still adding the core SDK when only a BOM is present.

Co-Authored-By: Claude <[email protected]>
Document the auto-install fix now that the pull request number is available.

Co-Authored-By: Claude <[email protected]>
Sentry's sentry-opentelemetry-* artifacts are built against specific
OpenTelemetry versions. When another dependency management mechanism -
most commonly Spring Boot's io.spring.dependency-management - forces
OpenTelemetry below the version Sentry's integration requires, running
against those downgraded versions can cause ClassNotFoundException /
NoSuchMethodError at runtime.

Add a JVM-only verifySentryOpenTelemetryVersions task that walks the
resolved runtimeClasspath graph and fails the build when an OpenTelemetry
module a sentry-opentelemetry-* artifact depends on resolves lower than
the requested version. The failure message adapts to the project setup:
it suggests importing the Sentry OpenTelemetry BOM via
io.spring.dependency-management when that plugin is applied, otherwise a
platform() dependency.

The check is gated by a cheap declared-dependency lookup so it is skipped
(no runtime classpath resolution) for projects that don't use Sentry
OpenTelemetry, and can be disabled via
sentry.autoInstallation.verifyOpenTelemetryVersions = false.

Co-Authored-By: Claude <[email protected]>
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 8ee4bdb

adinauer and others added 2 commits July 2, 2026 11:58
…heck

Remove comments that restated self-explanatory code (the verifyEnabled
property KDoc and two test comments that duplicated their assertions).

Co-Authored-By: Claude <[email protected]>
The springDependencyManagementApplied and hasSentryOpenTelemetryDependency
property names are self-explanatory, and the rationale already lives at the
usage sites (buildMessage and register).

Co-Authored-By: Claude <[email protected]>
Comment thread CHANGELOG.md Outdated
Co-authored-by: Alexander Dinauer <[email protected]>
@adinauer
adinauer marked this pull request as ready for review July 2, 2026 10:19

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together. Overall looks good. I left some comments, let me know if you'd like to discuss any of these.

adinauer and others added 2 commits July 6, 2026 14:51
Declare the verification task as non-cacheable because it only validates the resolved dependency graph and has no outputs.

Add integration coverage to assert the task stores and reuses Gradle's configuration cache.

Co-Authored-By: Claude <[email protected]>
adinauer and others added 6 commits July 6, 2026 15:07
Remove the outdated placeholder comment now that the troubleshooting docs PR exists.

Co-Authored-By: Claude <[email protected]>
Rename the internal version check data class to describe the downgrade it represents.

Co-Authored-By: Claude <[email protected]>
Include the Sentry OpenTelemetry artifact requesting each downgraded module and Gradle's selection reason when available.

This gives users more context about which integration was affected and why Gradle resolved the lower OpenTelemetry version.

Co-Authored-By: Claude <[email protected]>
Use the resolved Sentry OpenTelemetry artifact version in the suggested BOM coordinates instead of a placeholder.

This makes the failure message copy-pasteable and matches the version whose OpenTelemetry requirements were checked.

Co-Authored-By: Claude <[email protected]>
Move OpenTelemetry downgrade detection and message formatting out of the Gradle task so the task only handles wiring and execution.

Add focused unit coverage for artifact detection and failure message formatting.

Co-Authored-By: Claude <[email protected]>
Convert OpenTelemetry version check integration assertions from kotlin.test to Google Truth for clearer string assertion failures.

Co-Authored-By: Claude <[email protected]>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6a5a723. Configure here.

@adinauer
adinauer requested a review from runningcode July 7, 2026 04:13
Clean up the verifyOpenTelemetryVersions property documentation so formatting checks pass and the behavior is described clearly.

Co-Authored-By: Claude <[email protected]>

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks for the cleanup and adding the configuration cache test.

I realized we should separate integrationTests from unitTests into separate source directories/tasks but that is an already existing organization issue.

Expose the OpenTelemetry downgrade check directly on the Sentry plugin extension instead of under autoInstallation. This reflects that the check validates dependency resolution independently of auto-installation.

Refs #1350

Co-Authored-By: Claude <[email protected]>
Base automatically changed from side-quest/sagp-bom-version-use-skill-create to main July 14, 2026 06:21
adinauer added a commit to getsentry/sentry-maven-plugin that referenced this pull request Jul 14, 2026
#268)

Builds on top of #265. Maven port of
getsentry/sentry-android-gradle-plugin#1350 (which itself is stacked on
the SAGP equivalent of #265,
getsentry/sentry-android-gradle-plugin#1349).

## What

Fails the build when the OpenTelemetry versions resolved for a project
are **downgraded** below what Sentry's `sentry-opentelemetry-*`
artifacts were built and tested against.

## Why

Sentry's OpenTelemetry artifacts declare the exact OpenTelemetry
versions they require. When another dependency management mechanism —
most commonly Spring Boot (via `spring-boot-starter-parent` or an
imported `spring-boot-dependencies` BOM) — forces OpenTelemetry below
those versions, it happens **silently** (the user never declares an OTel
version). Running against the mismatched versions can throw
`ClassNotFoundException` / `NoSuchMethodError` at runtime. This surfaces
the problem at build time with actionable guidance instead.

This **replaces an earlier approach that auto-installed the BOM**
(previous PR #266). In Maven a late-injected import-scope BOM is a no-op
(BOM imports are flattened during effective-model building, before
`afterProjectsRead`), and rewriting inherited `dependencyManagement` in
place is too surprising. Detecting-and-failing is the more honest
behavior — same conclusion as SAGP #1350.

## How it works

- Runs in the lifecycle participant (automatic, no execution config
needed), reusing the dependency resolution already done for
auto-install.
- Gated by a cheap check: skipped entirely unless the project uses a
`sentry-opentelemetry-*` artifact.
- Resolves each present `sentry-opentelemetry-*` artifact to determine
the OpenTelemetry versions it requires (declared dependencies + its own
dependency management), then compares against the versions actually
resolved on the project. A resolved version lower than the required
version is a downgrade.
- Only OpenTelemetry modules a `sentry-opentelemetry-*` artifact
requires are inspected, so unrelated OpenTelemetry usage is never
flagged. Unparseable versions are skipped.
- The failure message lists each downgrade and shows the exact
`<dependencyManagement>` import for `sentry-opentelemetry-bom` at the
resolved Sentry version, noting Maven's first-declaration-wins ordering
when Spring Boot is present.

## Config

Opt out with
`<skipValidateOpenTelemetryVersions>true</skipValidateOpenTelemetryVersions>`.
Adds a `SENTRY_validateOpenTelemetryVersions` telemetry tag.

## Phase / placement

Implemented in the lifecycle participant (runs before any phase,
automatically) rather than as an opt-in `validate`-phase mojo, so users
get protected by default — matching SAGP #1350's automatic, default-on
behavior.

## Open items (mirroring SAGP #1350)

- **Docs URL is a placeholder**
(`.../platforms/java/tracing/instrumentation/opentelemetry/troubleshooting/`)
and must resolve to a live page before release.
- **Default-on is a product call.** Defaulting a build-breaking check to
on will surprise existing Spring Boot users on upgrade. Either keep
default-on with a clearly-flagged behavioral-change changelog entry, or
ship opt-in first and flip later based on telemetry.

## Tests

- Unit (`OpenTelemetryVersionCheckerTest`): downgrade detection (match /
upgrade / not-resolved / alpha / unparseable), eligibility gate, and
failure-message content (mismatch line, BOM snippet, opt-out, Spring
Boot ordering note).
- Integration (`OpenTelemetryVersionCheckTestIT`): build fails on a
Spring Boot parent downgrade with the guidance message; succeeds when
not downgraded; succeeds when disabled; no-op without a Sentry
OpenTelemetry dependency.

Co-authored with Claude.

---------

Co-authored-by: Claude <[email protected]>
@adinauer
adinauer merged commit a2e0e97 into main Jul 14, 2026
25 checks passed
@adinauer
adinauer deleted the side-quest/sagp-otel-version-check branch July 14, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants