Chapter 24Lesson 04~145 minutes

Monorepos, Multi-Module Builds, Generated Code, and Complex Repository Layouts: Diagnostics, Failure Modes, and Production Practices

Diagnose complex-layout failures by separating source scope, report resolution, project identity, scanner workspace, Compute Engine, policy, CI concurrency, and commercial aggregation instead of hiding symptoms with exclusions.

MonoreposModulesAnalysis scopeReport pathsGovernance

Learning objectives

  • Use an evidence-first diagnostic sequence for missing, duplicated, stale or cross-owned source/report results.
  • Diagnose shared project keys and shared scanner working directories without erasing first-failure artifacts.
  • Separate report-path defects from source indexing, Compute Engine, Quality Gate and provider failures.
  • Detect exclusions that hide first-party code instead of repairing ownership.
  • Recognize when a problem is Community/commercial feature expectation rather than a scanner defect.
  • Repair the smallest state surface and rerun the smallest equivalent analysis.

1. Evidence-first diagnostic sequence for complex layouts

  1. Preserve the exact Git SHA, CI job identity, scanner command/effective parameters, scanner log, report files and report-task.txt.
  2. Confirm server edition/version, scanner/runtime and build-tool/analyzer versions.
  3. Confirm project key, branch/revision identity and expected module owner.
  4. Resolve projectBaseDir, sonar.sources, sonar.tests, inclusions/exclusions and working directory.
  5. Inspect indexed-file evidence and report-import evidence independently.
  6. Inspect ceTaskId and Compute Engine terminal state.
  7. Inspect project measures/issues/gate/New Code state only after the analysis task is known.
  8. Inspect CI concurrency, provider decoration and aggregation only if the underlying project analysis is correct.
  9. Apply the least destructive correction and rerun the smallest equivalent scope at the same revision when possible.

2. Failure: overlapping analyses double-own the same first-party file

Symptom: shared/util.py appears in both repo-api and repo-worker, each with separate issues/metrics. This may be intentional if both projects truly ship a copy, but in a monorepo it often means both scanners claimed the same source path.

Preserve both scanners’ indexed-file evidence and project scopes. Then decide ownership. Options include one shared-library project, ownership by one component with consumers treated as dependencies, or deliberate duplicate ownership documented as such. Do not “fix” the dashboard by randomly excluding whichever project looks worse.

3. Failure: report path is relative to the wrong workspace

report exists + source indexed + no imported measure → resolve report parameter from projectBaseDir → inspect report-internal paths → repair coordinate only

This is the Chapter 24 deliberately broken case. The scanner may upload a report and the Compute Engine may succeed while a coverage sensor warns that the configured coverage file cannot be found. That is a scanner/build/report-layer defect, not a database or gate defect.

4. Failure: two modules reuse one project key

Symptom: API and worker pipelines both submit analysis to sq-service. The project’s history flips between different file populations, New Code becomes difficult to interpret, and one module’s analysis can effectively replace the other’s current project state.

Preserve both CI revisions, commands and task IDs. Repair the topology: either intentionally combine the modules into one analysis with one source scope, or assign distinct project keys. Do not create a random new key merely to make the current failed run disappear; the new key must come from the approved ownership model.

5. Failure: an exclusion makes the metric green by hiding owned code

# Suspicious shortcut
sonar.exclusions=modules/worker/**

If worker is part of the intended project, this does not repair a path or report defect—it changes the analyzed population. Preserve before/after file counts and explain the governance impact. Prefer correcting projectBaseDir, sources or report path. Use exclusions only when the ownership contract says those files do not belong.

6. Failure: parallel jobs overwrite scanner work or reports

Symptom: one job intermittently loses report-task.txt, coverage changes unpredictably, or scanner logs reference files created by another job.

Check whether jobs share:

  • the same checkout directory;
  • the same sonar.working.directory;
  • the same coverage/report output filename;
  • the same project key/branch identity;
  • the same artifact upload destination.

Repair isolation first. Distinct module projects can run in parallel with separate bases/workdirs/artifacts. Same-project runs should normally be serialized or superseded deterministically.

7. Failure: generated/vendor treatment changes silently

A generator upgrade may move output from generated/ into src/generated/. An exclusion pattern can stop matching, causing a sudden LOC/duplication/issue increase. Or a new broad pattern can hide first-party code accidentally.

Preserve generator version, Git diff, scope settings and indexed-file delta. Treat exclusion changes as policy changes. Test patterns against an explicit file inventory before applying them globally.

8. Failure: expecting SonarQube to infer business ownership

Even Enterprise monorepo onboarding requires projects to be created/configured; current documentation explicitly notes SonarQube cannot detect projects inside a monorepo automatically. Directory structure and build graph are technical signals, not authorization or business-ownership truth.

The repair is an ownership manifest and deterministic CI mapping, not a plugin that guesses team boundaries from folder names.

9. Intentionally broken example: interpret the evidence without hiding it

revision=7f00...cafe
projectKey=sq-ch24-worker
projectBaseDir=modules/worker
sources=src
tests=tests
coverageReportPath=modules/worker/coverage.xml
scannerExit=0
ceTaskId=AYx...
ceStatus=SUCCESS
indexedMainFiles=1
coverageImportWarning="report not found at configured path"
projectCoverage=<missing or zero-like result>

The causal diagnosis is not “SonarQube ignored coverage.” It is “the scanner’s project coordinate is modules/worker, while the configured report path redundantly includes that prefix.” The least destructive fix is coverage.xml, followed by a same-revision analysis and task/measure comparison.

10. Failure-layer map

Evidence Likely layer Next safe action
Directory in sonar.sources does not exist Base/scope configuration Resolve path from projectBaseDir; do not change server state.
File indexed, coverage report missing Producer/report path Inspect producer output and report parameter/internal paths.
Scanner succeeds, CE fails Server processing Preserve ceTaskId, CE error and server logs.
Two tasks for same key from different modules Project topology/CI concurrency Reconcile intended project boundary and serialize/rename by approved ownership.
Aggregate view absent in Community Build Edition capability Use project-level API summary fallback; do not install unverified plugins.
Generated files suddenly appear Build/scope policy drift Compare generator/output path and indexed-file inventory.

11. Production shortcuts to reject

  • Do not exclude uncovered modules to improve coverage.
  • Do not reuse one project key for unrelated module histories.
  • Do not make parallel jobs share .scannerwork or mutable report artifacts.
  • Do not delete scanner logs/report files before preserving first-failure evidence.
  • Do not directly edit SonarQube database/search state to remove a bad analysis.
  • Do not lower Quality Gate thresholds because a previously omitted module is now visible.
  • Do not invent Enterprise monorepo/application/portfolio behavior on Community Build.
  • Do not replace a failed project with a different key unless the approved topology itself changed.

Knowledge check

Two modules both analyze shared/util.py. What do you inspect before excluding it?

A scan exits 0 and CE succeeds, but coverage is absent. Which layer can still be wrong?

Why is a broad sonar.exclusions change dangerous during troubleshooting?

What is the first concurrency artifact to inspect when two jobs share one checkout?

Why can’t a Portfolio prove that underlying project boundaries are correct?

Next lesson

Produce the two-module topology checkpoint

Lesson 5 packages project/file/report ownership, deliberate failure evidence, task chains and edition-aware aggregation into a governed checkpoint.

Official references and version notes

Version and compatibility note

Rechecked 2026-09-08. Mandatory examples target Community Build 26.9.0.129388 and SonarScanner CLI 8.1.0.6389. For CLI-managed projects, sonar.projectBaseDir changes the analysis directory; sonar.sources/sonar.tests are simple paths relative to that base unless absolute. Most coverage/external report paths are project-root/base-relative unless their parameter docs state otherwise. sonar.working.directory must be unique for each project and is deleted before each analysis, so parallel jobs must isolate scanner/report artifacts. Current native monorepo onboarding/binding is an Enterprise Edition feature and still requires explicit projects; SonarQube does not infer monorepo projects automatically. Applications are a commercial aggregation starting in Developer Edition; Portfolios start in Enterprise Edition. Community Build can still model multiple independent projects from one repository manually with distinct project keys/base directories and an external governance-summary fallback. Recheck the exact scanner/build integration and report parameter semantics before production use.

Complex-layout evidence rule. Preserve repository root, exact revision, project key/owner, projectBaseDir, source/test roots, inclusions/exclusions, generated/vendor policy, report producer/path/internal filenames, unique scanner working directory, token owner/type (never value), scanner log, report-task.txt, ceTaskId, Compute Engine state, measures/gate, CI concurrency identity and aggregation edition/definition separately.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.