Skip to content

[java] publish selenium-devtools-latest alias artifact#17492

Closed
asolntsev wants to merge 1 commit into
SeleniumHQ:trunkfrom
asolntsev:java-devtools-latest-alias
Closed

[java] publish selenium-devtools-latest alias artifact#17492
asolntsev wants to merge 1 commit into
SeleniumHQ:trunkfrom
asolntsev:java-devtools-latest-alias

Conversation

@asolntsev
Copy link
Copy Markdown
Contributor

@asolntsev asolntsev commented May 17, 2026

Instead of writing

import org.openqa.selenium.devtools.v148.page.Page;

and updating "v148" part with every new release, now users can just write forever:

import org.openqa.selenium.devtools.latest.page.Page;

Similar to PR #17133, but for Java bindings.

Summary

  • Adds a new Maven artifact org.seleniumhq.selenium:selenium-devtools-latest that republishes the most recent supported CDP version under the stable org.openqa.selenium.devtools.latest package. Downstream consumers no longer have to bump a version-suffixed dependency (selenium-devtools-vNNN) each time Chrome ships a new major release.
  • Generated CDP code is produced by running CdpClientGenerator with "latest" against the protocol files of LATEST_CDP_VERSION; the hand-written shim classes are derived by sed-rewriting the corresponding files from the latest vNNN package at build time, so nothing is duplicated on disk.
  • LATEST_CDP_VERSION is computed as max(CDP_VERSIONS, key = lambda v: int(v[1:])) so the alias keeps pointing at the highest-numbered entry even after scripts/update_cdp.py rewrites versions.bzl in place (which can leave the list unsorted).
  • No source files inside the new latest/ directory — only BUILD.bazel. Adding a new CDP version (and removing the oldest) via ./go update_cdp continues to "just work"; the shim-sources filegroup added to v148/BUILD.bazel propagates forward through update_cdp.py's copy step.

Test plan

  • bazelisk build //java/src/org/openqa/selenium/devtools/latest:latest
  • Inspected latest-project.jar: contains both shim classes (latestCdpInfo, latestDomains, …) and all generated CDP domain classes (Fetch, Network, Target, …) under org/openqa/selenium/devtools/latest/, plus a META-INF/services/org.openqa.selenium.devtools.CdpInfo entry registering latestCdpInfo.
  • bazelisk build //java/src/org/openqa/selenium:client-combined //java/src/org/openqa/selenium/grid:grid — existing consumers of CDP_DEPS still build.
  • ./go format

🤖 Generated with Claude Code

@selenium-ci selenium-ci added C-java Java Bindings B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related labels May 17, 2026
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Add stable selenium-devtools-latest alias artifact for latest CDP version

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Introduces stable selenium-devtools-latest Maven artifact tracking newest CDP version
• Computes LATEST_CDP_VERSION dynamically to handle unsorted version lists
• Generates CDP code and derives shim classes via sed-rewriting from latest version
• Adds latest artifact to release targets and updates CDP maintenance documentation
Diagram
flowchart LR
  versions["versions.bzl<br/>LATEST_CDP_VERSION"]
  latest_build["latest/BUILD.bazel<br/>Generate & Rewrite"]
  v148_build["v148/BUILD.bazel<br/>shim-sources filegroup"]
  cdp_proto["CDP Protocol Files<br/>browser_protocol.json"]
  generator["CdpClientGenerator<br/>with 'latest' param"]
  shim_rewrite["sed-rewrite shim classes<br/>vNNN → latest"]
  maven["Maven Artifact<br/>selenium-devtools-latest"]
  
  versions -- "max CDP_VERSIONS" --> latest_build
  v148_build -- "provide shim sources" --> shim_rewrite
  cdp_proto -- "input" --> generator
  generator -- "generate CDP code" --> latest_build
  shim_rewrite -- "generate shim code" --> latest_build
  latest_build -- "produces" --> maven
Loading

Grey Divider

File Changes

1. java/src/org/openqa/selenium/devtools/versions.bzl ⚙️ Configuration changes +12/-1

Define LATEST_CDP_VERSION and add to CDP_DEPS

• Adds LATEST_CDP_VERSION computed as max of CDP_VERSIONS by numeric value
• Includes latest alias in CDP_DEPS list for downstream consumers
• Documents why numeric max is used instead of list indexing

java/src/org/openqa/selenium/devtools/versions.bzl


2. java/src/org/openqa/selenium/devtools/latest/BUILD.bazel ✨ Enhancement +103/-0

New latest alias package with generated and rewritten sources

• Creates new java_export target for stable selenium-devtools-latest Maven artifact
• Generates CDP code using CdpClientGenerator with "latest" parameter against LATEST_CDP_VERSION
 protocol files
• Derives shim classes via genrule that sed-rewrites latest version's shim sources
• Exports CDP library with proper dependencies and visibility

java/src/org/openqa/selenium/devtools/latest/BUILD.bazel


3. java/src/org/openqa/selenium/devtools/v148/BUILD.bazel ✨ Enhancement +10/-0

Export shim sources for latest alias rewriting

• Adds shim-sources filegroup exposing hand-written Java shim classes
• Restricts visibility to latest package for sed-rewriting
• Enables source reuse without duplication on disk

java/src/org/openqa/selenium/devtools/v148/BUILD.bazel


View more (2)
4. rake_tasks/java.rake ⚙️ Configuration changes +1/-0

Include latest alias in Maven release targets

• Adds //java/src/org/openqa/selenium/devtools/latest:latest.publish to release targets
• Ensures latest alias artifact is published alongside versioned CDP packages

rake_tasks/java.rake


5. java/src/org/openqa/selenium/devtools/README.md 📝 Documentation +5/-1

Document automatic latest alias updates in CDP maintenance

• Documents that LATEST_CDP_VERSION is automatically picked up from CDP_VERSIONS
• Explains that new CDP versions are republished under stable org.openqa.selenium.devtools.latest
 package
• Notes that users get new versions via stable selenium-devtools-latest coordinate without extra
 work

java/src/org/openqa/selenium/devtools/README.md


Grey Divider

Qodo Logo

Comment on lines +16 to +18
CDP_DEPS = ["//java/src/org/openqa/selenium/devtools/%s" % v for v in CDP_VERSIONS] + [
"//java/src/org/openqa/selenium/devtools/latest",
]
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.

Action required

1. Nondeterministic cdp provider 🐞 Bug ☼ Reliability

Adding //.../devtools/latest to CDP_DEPS puts both v148CdpInfo and the generated
latestCdpInfo (same major version) on the classpath, so CdpVersionFinder may return either one
for an exact match depending on Set iteration order. This can cause flaky behavior and makes
debugging provider selection harder because the exact CDP implementation chosen is no longer
deterministic.
Agent Prompt
## Issue description
`CDP_DEPS` now includes `//java/src/org/openqa/selenium/devtools/latest`, which introduces a second `CdpInfo` provider for the same major version as the newest `vNNN` package. `CdpVersionFinder` loads all providers into a `Set` and returns the first exact match it iterates over, so the chosen provider becomes non-deterministic.

## Issue Context
- `latestCdpInfo` is generated by string-rewriting the newest `vNNN` shims, so it keeps the same `super(<major>, ...)` major version (e.g. 148).
- `CdpInfo` does not override `equals/hashCode`, so both providers coexist in the `Set`.

## Fix Focus Areas
- java/src/org/openqa/selenium/devtools/versions.bzl[16-18]

### Suggested fix
Remove `//java/src/org/openqa/selenium/devtools/latest` from `CDP_DEPS` so the default Selenium artifacts don’t pull in both providers. Keep publishing `selenium-devtools-latest` via its own release target so downstream users can opt in explicitly.

(Alternative, if you *must* keep it in `CDP_DEPS`: make `CdpVersionFinder` deterministically resolve ties when multiple `CdpInfo` instances report the same `majorVersion`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@asolntsev asolntsev force-pushed the java-devtools-latest-alias branch from c3f65cb to a237baf Compare May 17, 2026 19:14
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 17, 2026

Persistent review updated to latest commit a237baf

Comment thread scripts/prepare_idea_java_project.sh Outdated
Adds a stable Maven coordinate that always tracks the newest supported
CDP version. The new //java/src/org/openqa/selenium/devtools/latest
target republishes the most recent vNNN package under
org.openqa.selenium.devtools.latest, so downstream users no longer have
to bump a version-suffixed dependency every time Chrome ships a new
major release.

The generated CDP code is produced by running CdpClientGenerator with
"latest" against the protocol files of LATEST_CDP_VERSION, and the
hand-written shim classes are derived by sed-rewriting the latest
version's shim sources at build time. LATEST_CDP_VERSION is computed
as max(CDP_VERSIONS) so the alias remains correct after
scripts/update_cdp.py rewrites versions.bzl in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@asolntsev asolntsev force-pushed the java-devtools-latest-alias branch from a237baf to 8d568c8 Compare May 17, 2026 19:21
@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 17, 2026

Persistent review updated to latest commit 8d568c8

@SeleniumHQ SeleniumHQ deleted a comment from qodo-code-review Bot May 17, 2026
@titusfortner
Copy link
Copy Markdown
Member

Except this will end up being the default people use even if things get out of sync. Maybe we label it @beta or call it unstable instead of latest as a warning to users?
One of the reasons we supported it this way was to highlight the potential issues with CDP, and to encourage the switch to BiDi (which obviously is a better argument when we actually support BiDi)

We probably need to delete @AutoService annotation for it as well

@asolntsev
Copy link
Copy Markdown
Contributor Author

Except this will end up being the default people use even if things get out of sync. Maybe we label it @beta or call it unstable instead of latest as a warning to users? One of the reasons we supported it this way was to highlight the potential issues with CDP, and to encourage the switch to BiDi (which obviously is a better argument when we actually support BiDi)

We probably need to delete @AutoService annotation for it as well

Users are very different.
I assume most users (including me) use only a very small set of CDP functions that almost never change.
For such users, "latest" is just perfect.
We don't want to change these versions with every browser update. It's a waste of time.
And yes, we are always ready for the risk that something might go wrong after updating browser/selenium/selenide/java/gradle etc. It's not a big deal, it's just our everyday job.

Copy link
Copy Markdown
Member

@diemol diemol left a comment

Choose a reason for hiding this comment

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

Do we still show a warning when the browser version is higher than the ones the Selenium version the user has is offering?

@asolntsev
Copy link
Copy Markdown
Contributor Author

Do we still show a warning when the browser version is higher than the ones the Selenium version the user has is offering?

Yes, just checked with Selenium 4.43.0:

May 18, 2026 7:48:54 PM org.openqa.selenium.devtools.CdpVersionFinder findNearestMatch
WARNING: Unable to find an exact match for CDP version 148, returning the closest version; found: 147; Please update to a Selenium version that supports CDP version 148

Copy link
Copy Markdown
Member

@diemol diemol left a comment

Choose a reason for hiding this comment

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

I actually like the idea. Would be nice to add a note in the JavaDocs about the potential side effects.

@titusfortner
Copy link
Copy Markdown
Member

Implementation issues, though. What if we make selenium-devtools-latest a thin alias over the current vXXX artifact rather than a self-contained copy.

With this PR code as implemented, the new artifact ships its own sed-rewritten shim classes (latestCdpInfo, latestDomains, etc.) with @autoservice(CdpInfo.class). That creates a duplicate CdpInfo registration for the same major version when both selenium-devtools-latest and selenium-devtools-v are on the classpath (which is the default for selenium-java consumers, since CDP_DEPS now contains both). ServiceLoader returns both, and CdpVersionFinder.findNearestMatch exact-matches on whichever is iterated first — functionally equivalent, but observably non-deterministic and a noticeable jar-size duplication.

An alternative design that I think is cleaner:

  • selenium-devtools-latest contains only the generated CDP protocol types under org.openqa.selenium.devtools.latest.* (Page, Network, Fetch, etc. — the things users actually import).
  • Drop the shim entirely from this artifact (no latestCdpInfo, no latestDomains, no @autoservice).
  • Declare a Maven dependency on selenium-devtools-v<LATEST_CDP_VERSION> so the actual CdpInfo registration is provided transitively by the versioned artifact.

Trade-offs this resolves:

  1. No duplicate registration, ever. v148CdpInfo is the only registered impl for major 148; latest is purely an alias namespace.
  2. No shim file maintenance. The hardcoded outs list in create-shim-srcs, the shim-sources filegroup in v148/BUILD.bazel, and the spotbugs NM_CLASS_NAMING_CONVENTION exemption all
    go away. No risk of a future v149Foo.java being silently dropped from the alias.
  3. mvn dependency:tree is self-documenting — users see selenium-devtools-latest → selenium-devtools-v148 and know which CDP version they're actually running.
  4. No behavioral drift risk between v148Domains and a sed-copy latestDomains, because the sed-copy doesn't exist.

User-facing experience is identical: imports like org.openqa.selenium.devtools.latest.page.Page still work, Selenium upgrades pick up the new CDP under the same coordinate, Chrome
upgrades degrade gracefully via the existing fudge-factor logic.

@asolntsev
Copy link
Copy Markdown
Contributor Author

@titusfortner Sorry, I didn't understand what means "thin alias".

For the end user, the only important thing that I don't want to change this import every time:

import org.openqa.selenium.devtools.v148.page.Page;

Instead, I want to have the constant import:

import org.openqa.selenium.devtools.latest.page.Page;

How exactly it's achieved - it doesn't matter.
But essentially, this "thin alilas" needs to contain classes like Page in a different packages ("latest").

@titusfortner
Copy link
Copy Markdown
Member

@asolntsev I was also making it too complicated. We can just let the generator do all of the work and avoid all the problems: #17562 I built it and everything looks correct.

@asolntsev
Copy link
Copy Markdown
Contributor Author

Seems that #17562 works and fully solves the problem.
Thank you @titusfortner!

@asolntsev asolntsev closed this May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations B-devtools Includes everything BiDi or Chrome DevTools related C-java Java Bindings Compliance violation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants