Skip to content

[ci] Fix Java.Interop test lanes on internal 1ES pipeline - #11957

Merged
simonrozsival merged 5 commits into
mainfrom
jonathanpeppers-fix-java-interop-1es-pools
Jul 3, 2026
Merged

[ci] Fix Java.Interop test lanes on internal 1ES pipeline#11957
simonrozsival merged 5 commits into
mainfrom
jonathanpeppers-fix-java-interop-1es-pools

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Why

After merging external/Java.Interop in-tree, the new Java.Interop Tests stage started failing on the internal DevDiv Xamarin.Android pipeline (e.g. build 14551960) with:

1ES PT Error: Using a non 1ESHostedPool with 1ES PT is not allowed.

Both the Windows - .NET and Mac - .NET jobs failed in 1ES PT Pre-Job before doing any real work.

Root cause

The internal pipeline extends MicroBuild.1ES.Official.yml, which requires Windows jobs to run on a 1ES-hosted pool. stage-java-interop-tests.yaml was called with no parameters, so both jobs fell back to the template defaults - name: Azure Pipelines with no os: field. 1ES PT's validateHostedPool.ps1 defaults to -OS windows when the pool has no os:, then rejects the hosted Azure Pipelines pool as non-1ES - so even the Mac job was validated as Windows and rejected.

What changed

  • stage-java-interop-tests.yaml: set os: windows / os: macOS on the default pools so callers who omit the parameter still land on a valid setup, with a comment noting the Windows default is not Official-1ES compliant and must be overridden by Official callers.
  • azure-pipelines.yaml (internal): override windowsPool to MAUI-1ESPT + $(WindowsPoolImage1ESPT) + os: windows, matching the other internal Windows jobs. The Mac lane stays on hosted Azure Pipelines + os: macOS because 1ES has no macOS-hosted pool.
  • azure-pipelines-public.yaml: add os: windows on windowsPool for parity.
  • external/Java.Interop/build-tools/automation/templates/core-tests.yaml: declare runNativeDotnetTests as an actual parameter. It was referenced from the Java.Interop-Tests step's condition: but never declared, so it evaluated to '' at template expansion and that test step was silently skipped on Windows. Declaring the parameter lets the Windows lane's runNativeDotnetTests: true value take effect.

Testing

No new automated tests; the pipeline itself is the test. Once merged, the next internal run should show Java.Interop Tests reaching real build/test steps instead of failing in 1ES PT Pre-Job, and the Windows Java.Interop-Tests test step should actually execute.

jonathanpeppers and others added 2 commits July 2, 2026 08:12
The internal DevDiv Xamarin.Android pipeline (azure-pipelines.yaml)
extends MicroBuild.1ES.Official.yml, whose 1ES Pipeline Templates
require Windows jobs to run on a 1ES-hosted pool. The Java.Interop
test stage introduced with the Java.Interop merge was calling
stage-java-interop-tests.yaml with no parameters, so both the
`Windows - .NET` and `Mac - .NET` jobs fell back to the template
defaults - `name: Azure Pipelines` with no `os:` set.

1ES PT's validateHostedPool.ps1 defaults to `-OS windows` when the
pool has no `os:` field, and then rejects the hosted `Azure Pipelines`pool as `not a 1ESHostedPool`, failing both jobs in `1ES PT Pre-Job`.

Fix:
* Set `os: windows` / `os: macOS` on the template's default pools so
  callers that omit the parameter still land on a compliant setup.
* Override the internal pipeline to run the Windows lane on `MAUI-1ESPT`+ `WindowsPoolImage1ESPT`, matching the other Windows jobs in the
  pipeline. The Mac lane can stay on hosted `Azure Pipelines` because
  1ES has no macOS 1ES-hosted pool; `os: macOS` alone is enough.
* Also set `os: windows` on the public pipeline's windowsPool for
  parity and safety.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add a comment to stage-java-interop-tests.yaml explaining the
  windowsPool default is not 1ES-Official compliant and must be
  overridden by Official callers.
* Declare `runNativeDotnetTests` in external/Java.Interop's
  core-tests.yaml. The parameter was referenced from the `Java.Interop-Tests`condition but never declared, so it evaluated to '' at expansion and
  the Windows Java.Interop-Tests step was silently skipped.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 2, 2026 13:39
@jonathanpeppers

jonathanpeppers commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Copilot AI 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.

Pull request overview

Fixes the internal 1ES DevDiv pipeline’s Java.Interop Tests stage by ensuring pool definitions include an explicit os: and by wiring a previously-referenced-but-undeclared Java.Interop template parameter so the intended Windows test step actually runs.

Changes:

  • Add explicit os: windows / os: macOS to the default pools in the shared Java.Interop test stage template to satisfy 1ES PT hosted-pool validation behavior.
  • Override the Java.Interop Windows pool in the internal azure-pipelines.yaml to use the 1ES-hosted MAUI-1ESPT pool + image.
  • Declare runNativeDotnetTests as a parameter in the Java.Interop core-tests.yaml template so the Windows lane’s runNativeDotnetTests: true takes effect (instead of being silently skipped).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
external/Java.Interop/build-tools/automation/templates/core-tests.yaml Declares runNativeDotnetTests parameter so the Java.Interop-Tests step condition can be driven by callers.
build-tools/automation/yaml-templates/stage-java-interop-tests.yaml Adds os: to default pools (Windows/macOS) and documents 1ES Official mode requirements for Windows pools.
build-tools/automation/azure-pipelines.yaml Internal pipeline now overrides windowsPool for the Java.Interop stage to a 1ES-hosted pool.
build-tools/automation/azure-pipelines-public.yaml Adds os: windows on the Java.Interop stage’s Windows pool for parity/consistency.

Comment thread build-tools/automation/yaml-templates/stage-java-interop-tests.yaml
jonathanpeppers and others added 2 commits July 2, 2026 09:54
The Mac lane in build 14553565 crashed with:

    FAILURE: Build failed with an exception.
    * What went wrong:
    BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_'
    Unsupported class file major version 69

Major version 69 is Java 25. The hosted macOS-15-arm64 image now ships
Java 25 as its default JDK, and Gradle 8.12 (used by java-source-utils
and tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle) does not
support Java 25.

The rest of the dotnet/android pipeline avoids this by calling the
setup-jdk-variables.yaml template, which pins JAVA_HOME to a specific
agent JDK. The Java.Interop stage was skipping that step and inheriting
the agent default.

Add setup-jdk-variables.yaml to both the Windows and Mac Java.Interop
jobs, pinned to $(LatestJavaSdkMajorVersion) (21, defined in
build-tools/automation/yaml-templates/variables.yaml), matching the
rest of the pipeline. Windows did not fail this run but will hit the
same issue once its hosted image bumps default JDK.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The Java.Interop Mac test lane (dotnet/android build 14553956) failed
with Gradle 8.12 rejecting "Unsupported class file major version 69"
even after the pipeline pinned JAVA_HOME to Java 21 via
setup-jdk-variables.yaml.

Root cause: Prepare.targets is what actually decides which JDK the rest
of the build uses. It runs the JdkInfo bootstrap task, which discovers
a JDK and writes bin/BuildRelease/JdkInfo.props. Every downstream .targets
file that shells out to Gradle passes EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory);..."
to <Exec>, overriding whatever JAVA_HOME the process inherited.

JdkInfo prefers an explicit JdksRoot when given one; otherwise it walks
GetKnownSystemJdkInfos and takes the first hit. Prepare.targets only set
JdksRoot from JAVA_HOME_17_X64 / JAVA_HOME_11_X64 - Azure Pipelines
variables that exist only on x64 hosted agents. On macOS-15-arm64
(and any other arm64 or non-Azure-Pipelines environment) both were
empty, JdksRoot stayed unset, and JdkInfo picked the newest system JDK
- Java 25 on the current hosted image - blowing up Gradle.

Add a third fallback: use $JAVA_HOME itself when it is set and points
to an existing directory. This is what any pipeline or developer who
has already selected a JDK expects, and it matches how the rest of
dotnet/android's build steps propagate JAVA_HOME.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
Member Author

The previous attempt used setup-jdk-variables.yaml with useAgentJdkPath=true
to point JAVA_HOME at the agents preinstalled JDK. That works on the
internal DevDiv MAUI-1ESPT / hosted Azure Pipelines images (which set
JAVA_HOME_21_X64), but the dnceng-public NetCorePublicPool image does
not preinstall JDK 21, so the step failed with:

    Get-Item : Cannot find path Env:\JAVA_HOME_21_X64 because it does not exist.

It was also fragile at another layer: the Java.Interop MSBuild targets
that shell out to Gradle pass EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory)"
on every <Exec>, so pipeline JAVA_HOME gets overridden anyway. What
actually matters is which JDK Prepare.targets JdkInfo bootstrap task
picks.

Simpler fix: set JI_MAX_JDK=21 as a stage-scope variable. Prepare.targets
already reads it via <_MaxJdk Condition=" $(_MaxJdk) == "> ${JI_MAX_JDK}
and forwards it to JdkInfo as MaximumJdkVersion. That caps the JDK to
one Gradle 8.12 supports on every agent, regardless of which JAVA_HOME_*
env vars the pool happens to preinstall.

Remove the pipeline JAVA_HOME juggling and drop the setup-jdk-variables
calls I added for the Java.Interop jobs. The Prepare.targets $JAVA_HOME
fallback added in the previous commit stays put - it is still a real
improvement for local devs who export JAVA_HOME.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival merged commit 6a1cc0f into main Jul 3, 2026
42 checks passed
@simonrozsival
simonrozsival deleted the jonathanpeppers-fix-java-interop-1es-pools branch July 3, 2026 06:54
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants