Skip to content

ci: migrate Sonar analysis to @3 tasks and Java 21#589

Open
alexandru-petre wants to merge 8 commits into
developfrom
fix/sonar-java21-tasks-v3
Open

ci: migrate Sonar analysis to @3 tasks and Java 21#589
alexandru-petre wants to merge 8 commits into
developfrom
fix/sonar-java21-tasks-v3

Conversation

@alexandru-petre

@alexandru-petre alexandru-petre commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Context

The activity packs run SonarCloud analysis through vendored pipeline templates under Activities/.pipelines/templates/ (not the shared @common repo). The scan is split across two stages: SonarCloudPrepare (begin) runs in the Build stage, while SonarCloudAnalyze/SonarCloudPublish (end) run in a separate PublishSonar job — homemade upload/download/patch steps ferry the scanner and its state between them. All six packs share this chain via stage.start.yml -> stage.sonar.yml.

Problem Statement

SonarQube Cloud no longer supports Java 17 and fails the analysis: "The version of Java (17) ... is deprecated ... upgrade to Java 21 or later." Every pack's Sonar stage is red.

Behavior Before This PR

The Sonar stage runs the legacy SonarCloud*@1 tasks with no JDK selection; the scanner picks the agent's default Java 17 and the end step aborts with the deprecation error. No coverage or quality gate is published.

Behavior After This PR

The @3 tasks run the analysis on Java 21 (jdkversion: JAVA_HOME_21_X64); the scanner and its v3 task state cross the Build -> PublishSonar boundary intact, the end step completes, and the quality gate publishes.

Implementation

Bumping @1 -> @3 alone was insufficient: SonarCloudPrepare@3 moved its cross-task variables to the SONAR_* namespace (SONAR_SCANNER_MODE, SONAR_ENDPOINT, SONAR_SCANNER_REPORTTASKFILE, SONAR_SERVER_VERSION; only SONARQUBE_SCANNER_PARAMS kept its old name) and its scanner-path vars (SONAR_SCANNER_DOTNET_EXE/DLL). Because this repo splits the tasks across stages, the upload/download/transfer steps were updated to carry the v3 names — Analyze@3 hard-fails without SONAR_SCANNER_MODE, Publish@3 without SONAR_ENDPOINT. Names verified against SonarSource's sonarcloud-v3 TaskVariables enum. The report-task-file is re-pointed to the PublishSonar job's temp dir without isOutput, so the same-job tasks read the rewrite.

Caveats / Potential Issues

  • Extension prerequisite: the @3 tasks require the SonarQube Cloud (v3) AzDO extension installed org-wide, or the pipeline fails to compile ("A task is missing").
  • PatchSonarQubeTask@0.7921.14273 pin (stage.sonar.yml) is unchanged — confirm it stays valid against the installed extension payload.
  • Cross-stage propagation of the secret SONAR_ENDPOINT could not be validated statically; it needs a real run.

How to Test

  • Trigger a pack pipeline (push a change under Activities/Java/*, or queue it manually) and confirm: (1) the pipeline compiles, and (2) the RunSonar job's "Run Code Analysis" step completes without the Java-version error and the quality gate publishes.

🤖 Generated with Claude Code

alexandru-petre and others added 2 commits July 23, 2026 19:01
SonarQube Cloud no longer supports Java 17. The vendored Sonar templates
used the old SonarCloud{Prepare,Analyze,Publish}@1 tasks, which have no
JDK-selection input, so the scanner ran on the agent's default Java 17.

Bump all three tasks to @3 and pass jdkversion: JAVA_HOME_21_X64 to the
Analyze task, matching the @common templates. Covers all activity packs
via the shared stage.sonar.yml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The @1 -> @3 task bump alone was insufficient: SonarCloudPrepare@3 publishes
v3-namespaced variables that this repo's cross-stage (Build -> PublishSonar)
scanner handoff did not carry.

- upload/download: probe and republish the v3 scanner-path variables
  (SONAR_SCANNER_DOTNET_EXE/DLL) alongside the legacy names.
- upload setSonarVariables + stage.sonar.yml: transfer the v3 task-state
  variables across the stage boundary using the names the @3 tasks actually
  read/require (SONAR_SCANNER_MODE, SONAR_ENDPOINT, SONAR_SCANNER_REPORTTASKFILE,
  SONAR_SERVER_VERSION; SONARQUBE_SCANNER_PARAMS keeps its legacy name), verified
  against SonarSource's v3 TaskVariables enum.
- stage.sonar.yml: patch SONAR_SCANNER_REPORTTASKFILE to the PublishSonar job's
  temp path (no isOutput, so the in-job Analyze/Publish tasks read the rewrite).

Cross-validated with Codex (4 rounds, final verdict: no findings).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandru-petre
alexandru-petre marked this pull request as ready for review July 23, 2026 17:14
@alexandru-petre alexandru-petre changed the title Fix SonarCloud analysis: migrate Sonar tasks to @3 and Java 21 fix(pipeline): migrate Sonar tasks to @3 and Java 21 Jul 23, 2026
@alexandru-petre alexandru-petre changed the title fix(pipeline): migrate Sonar tasks to @3 and Java 21 ci: migrate Sonar analysis to @3 tasks and Java 21 Jul 23, 2026
@alexandru-petre
alexandru-petre requested a review from Copilot July 23, 2026 17:20

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

Pull request overview

Updates the vendored Azure Pipelines SonarCloud templates to use the SonarCloud v3 (@3) tasks and run analysis with Java 21, while keeping the existing two-stage “prepare in Build / analyze+publish in PublishSonar” split working by propagating the renamed v3 SONAR_* variables and patching the report-task file path.

Changes:

  • Migrate SonarCloud tasks from @1 to @3 across prepare/analyze/publish templates.
  • Run Sonar analysis on Java 21 via SonarCloudAnalyze@3 jdkversion: JAVA_HOME_21_X64.
  • Update cross-stage artifact/variable ferrying for v3 (SONAR_* variables, scanner-path env var probing) and patch SONAR_SCANNER_REPORTTASKFILE in the PublishSonar job.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Activities/.pipelines/templates/stage.sonar.yml Imports v3 Sonar variables from Build stage outputs and patches SONAR_SCANNER_REPORTTASKFILE for the PublishSonar agent temp directory.
Activities/.pipelines/templates/Sonar/upload-sonar-build-output.yml Extends scanner-path discovery to support both v1 and v3 env var names; exports v3 SONAR_* variables plus original temp path as outputs.
Activities/.pipelines/templates/Sonar/download-sonar-build-output.yml Restores scanner-path variables in the PublishSonar job for both v1 and v3 env var names.
Activities/.pipelines/templates/Sonar/publish-sonar-coverage.yml Switches Quality Gate publish task to SonarCloudPublish@3.
Activities/.pipelines/templates/Sonar/prepare-sonar-coverage.yml Switches prepare task to SonarCloudPrepare@3.
Activities/.pipelines/templates/Sonar/analyze-sonar-coverage.yml Switches analyze task to SonarCloudAnalyze@3 and selects Java 21.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Activities/.pipelines/templates/Sonar/upload-sonar-build-output.yml
@alexandru-petre alexandru-petre self-assigned this Jul 23, 2026
Address PR review: replace non-terminating Write-Error with throw in the
upload/download scanner-path steps so the job aborts with a clear message
instead of continuing into an empty Copy-Item / missing-scanner secondary failure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@UiPath UiPath deleted a comment from azure-pipelines Bot Jul 23, 2026
SonarScanner for .NET 10.x auto-provisions its own JRE on the Build agent at
'begin' and bakes that agent-local path into <JavaExePath> in
SonarQubeAnalysisConfig.xml. The config is relocated to the separate RunSonar
agent, where the path does not exist, so the scanner's JAVA_HOME check failed at
'end' ("JAVA_HOME ... does not point to a valid Java home folder").

Repoint <JavaExePath> at the RunSonar agent's local JDK 21 (JAVA_HOME_21_X64,
pre-installed on windows-latest) before the analyze task. Mirrors the fix merged
in UiPath/Activities#38694.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread Activities/.pipelines/templates/Sonar/analyze-sonar-coverage.yml Fixed
Comment thread Activities/.pipelines/templates/Sonar/publish-sonar-coverage.yml Fixed
Pin SonarCloudPrepare/Analyze/Publish to the reviewed version 3.4.3 instead of
the floating @3. Floating major-version tags auto-adopt future 3.x releases
without review, which is the supply-chain exposure flagged by GitHub Advanced
Security (azurepipelines:S7637). Consistent with the existing
PatchSonarQubeTask@0.7921.14273 pin.

Note: these pins must be bumped in lockstep when the AzDO SonarQube Cloud
extension is updated, or the pipeline fails to compile ("A task is missing").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread Activities/.pipelines/templates/stage.sonar.yml Outdated
Comment thread Activities/.pipelines/templates/Sonar/prepare-sonar-coverage.yml Outdated
Comment thread Activities/.pipelines/templates/Sonar/upload-sonar-build-output.yml Outdated
Comment thread Activities/.pipelines/templates/Sonar/analyze-sonar-coverage.yml Outdated
@LiviuPonova

Copy link
Copy Markdown
Contributor

Non-blocking architectural observation: repeated ad hoc path-patching across split Prepare/Analyze/Publish jobs

Not a defect in this PR — just a pattern worth flagging for the team to weigh, since it keeps recurring.

This pipeline splits Sonar work across separate jobs/agents: "Prepare" runs on one agent (downloading the scanner, generating config files with that agent's local paths baked in), while "Analyze" and "Publish" run later on a different agent. Whenever the generated config references an agent-specific path, it breaks across that agent boundary, and the fix so far has been a bespoke find/replace "patch" step per broken path.

This PR adds two more such patches in stage.sonar.yml (the SONAR_SCANNER_REPORTTASKFILE path around line 57, and the JavaExePath patch around line 68), on top of the pre-existing PatchSonarQubeTask step. That's 3 separate hand-written patches now, each targeting a different property that broke for the same underlying reason.

Functionally this is fine and the PR's fixes look reasonable on their own. Just flagging that every future SonarScanner/SonarCloud extension change that bakes in a new agent-local path will likely need patch #4, #5, etc. It might be worth a future discussion on whether running prepare/analyze/publish in the same job/agent (or another way of avoiding the cross-agent path issue at the source) would be more sustainable than continuing to add patches — but that's an architectural call for the team, not something this PR needs to solve.

Comment thread Activities/.pipelines/templates/Sonar/upload-sonar-build-output.yml

@LiviuPonova LiviuPonova 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.

Approving — the overall direction (fixing the JDK-21/agent mismatch and hardening the scanner-path lookup) is solid, and I left 6 review comments (5 inline + 1 general) with suggested follow-ups.

One item is worth calling out explicitly before merge: the new fail-fast throw in upload-sonar-build-output.yml (missing Sonar Scanner directory) currently sits inside a step marked continueOnError: true, so it can never actually fail the job — the intended hardening doesn't take effect yet. Please take a look at that one in particular; the rest are lower-severity cleanup/maintainability notes (hardcoded task version repeated across files, a duplicated env-var alias list, JDK version hardcoded in two places) plus one non-blocking architectural observation about the growing number of ad hoc path patches across the split Prepare/Analyze/Publish jobs.

Approving on the basis that these get addressed before/at merge.

- stage.sonar.yml: gate the report-task-file patch behind RunAnalysis (like its
  sibling steps) and guard the .Replace() against an empty OriginalTempPath, which
  would otherwise throw ArgumentException and fail the job.
- upload-sonar-build-output.yml: add a separate "Verify Sonar scanner was staged"
  step without continueOnError, so a missing scanner actually fails the job (the
  copy step's throw was neutralized by its pre-existing continueOnError: true).
- Hoist the SonarCloud task version to a single source of truth: sonarTaskVersion
  in stage.start.yml, threaded to prepare/analyze/publish, instead of repeating
  the literal 3.4.3 in four places. Bump one spot on future extension updates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandru-petre

Copy link
Copy Markdown
Collaborator Author

Fixed in 36ad237: added a separate Verify Sonar scanner was staged step (without continueOnError) right after the copy step, so a missing scanner now fails the job instead of publishing an incomplete artifact. I left the copy step's pre-existing continueOnError: true untouched to avoid changing the behavior of its other branches (RoslynCA copy / symlink).

alexandru-petre and others added 2 commits July 24, 2026 19:02
Address two further review findings on duplicated literals:
- JDK env-var name (JAVA_HOME_21_X64) was in the analyze jdkVersion default and
  again in the stage.sonar.yml JavaExePath patch step. Hoisted to sonarJdkVersion
  in stage.start.yml, threaded to both.
- The 8 scanner-path variable names were hand-synced between the upload probe and
  the download republish. Hoisted to sonarScannerVarsDll/sonarScannerVarsExe in
  stage.start.yml; both templates now derive their lists from these.

Each value is now a single literal in stage.start.yml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…8263)

The single-source hoist interpolated ${{ parameters.* }} directly into inline
PowerShell blocks, which SonarCloud flags as BLOCKER script-injection
vulnerabilities (azurepipelines:S7630 / S8263) - pipeline parameters are treated
as untrusted input. This gave new code an E security rating and failed the gate.

Pass the parameters through each step's env: mapping and read them as $env:*
inside the scripts (the rule's sanctioned mitigation). The values still come from
the single source in stage.start.yml; only the delivery channel changed. The
task-version reference is unaffected (not a script block).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

4 participants