Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM maven:3.9.16-eclipse-temurin-21@sha256:99e61abcff91a9b1333463bd8451fb18495d6eba9250ac66a338b518f8278320
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 git \
&& rm -rf /var/lib/apt/lists/*
6 changes: 6 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Analyzer commons (JDK 21, Maven 3.9.16)",
"build": {"dockerfile": "Dockerfile"},
"postCreateCommand": "python3 scripts/dev.py doctor --resolve",
"remoteUser": "root"
}
23 changes: 23 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

[*.py]
indent_size = 4

# Test resources can contain intentional whitespace and invalid source.
[{*.py,*.yml,*.yaml,*.md}]
trim_trailing_whitespace = true

[**/src/test/resources/**]
charset = unset
end_of_line = unset
insert_final_newline = unset
indent_style = unset
indent_size = unset
trim_trailing_whitespace = false
2 changes: 2 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
exec python3 scripts/dev.py check --base HEAD
2 changes: 2 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Read [AGENTS.md](../AGENTS.md) before work. Follow the relevant module's
`AGENTS.md` for its code paths, test conventions, and generated data.
46 changes: 46 additions & 0 deletions .github/workflows/agent-readiness.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Repository checks

on:
pull_request:
types: [opened, synchronize, reopened, edited, labeled, unlabeled]
Comment thread
gitar-bot[bot] marked this conversation as resolved.
Resolved
push:
branches: [master, 'branch-*']
workflow_dispatch:

permissions:
contents: read

jobs:
local-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Check source boundaries, added credentials, and tooling tests
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before || github.sha }}
PR_TITLE: ${{ github.event.pull_request.title }}
ALLOW_LARGE: ${{ contains(github.event.pull_request.labels.*.name, 'large-change-reviewed') }}
run: |
if ! git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null; then
BASE_SHA="$(git rev-list --max-parents=0 HEAD | head -n 1)"
fi
python3 scripts/dev.py check --base "$BASE_SHA"
if [ -n "$PR_TITLE" ]; then
if [ "$ALLOW_LARGE" = true ]; then
python3 scripts/repository_checks.py --base "$BASE_SHA" --title "$PR_TITLE" --allow-large
else
python3 scripts/repository_checks.py --base "$BASE_SHA" --title "$PR_TITLE"
fi
fi

dependency-review:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Reject new high and critical dependency advisories
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ jobs:
sonar-platform: none
maven-args: -Pcoverage

- name: Generate dependency SBOM
run: mvn -B -ntp -C org.cyclonedx:cyclonedx-maven-plugin:2.9.1:makeAggregateBom

- name: Upload Maven build as pipeline artifact
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ Desktop.ini

# ---- Claude Code
.mcp.json

# Python command-tool bytecode
__pycache__/
*.pyc
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"editorconfig.editorconfig",
"sonarsource.sonarlint-vscode"
]
}
151 changes: 151 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Work in this repository

This repository contains eight shared Java libraries. It does not contain a
standalone analyzer or a SonarQube server. Start with the module table in
[README.md](README.md). Read only the module instructions that apply to the task.

## Prepare and check

Use Python 3.9 or later, Git, JDK 21, and Maven 3.9.16. `mise.toml` pins the local
JDK and Maven versions. From the repository root, run:

```sh
mise trust
mise install
python3 scripts/dev.py doctor --resolve
python3 scripts/dev.py test recognizers
```

`doctor` checks the JVM used by Maven. That JVM can differ from `java` on PATH.
The parent POM is `org.sonarsource.parent:parent`. Local tests do not require
Vault, a SonarQube server, npm, NuGet, or publishing credentials. If an artifact
returns HTTP 401 or 403, check your Maven mirror and server settings. Keep those
settings outside Git. Do not print tokens or copy CI deployer credentials.
The optional `.devcontainer` uses a base image fixed by digest. It installs Git
and Python from Debian packages. Those package versions are not locked.

## Select work and tests

```sh
python3 scripts/dev.py affected origin/master
python3 scripts/dev.py test commons --test TokenLocationTest
python3 scripts/dev.py test regex-parsing --test EmptyGroupFinderTest
python3 scripts/dev.py repeat recognizers --test CodeRecognizerTest
python3 scripts/dev.py verify
python3 scripts/dev.py build
python3 scripts/dev.py sbom
python3 scripts/dev.py reproduce recognizers
python3 scripts/dev.py quality recognizers
```

`affected` includes local edits and reverse dependencies, including test
dependencies. It gives a conservative module list. It cannot identify external
analyzer consumers. Module names are directory names. The Maven commands include
`-pl` and `-am` for selected modules. A class selector uses
`-Dsurefire.failIfNoSpecifiedTests=false` so upstream modules can have no matching
class. Always run the module suite after a focused test.
The tool also requires a fresh report with executed tests in the selected
module. A misspelled class or method fails instead of passing silently.

`test` runs unit tests. `verify` also runs the offline repository checks and
Maven verification, including the existing JAR size limits. `build` installs
artifacts in the local Maven cache. None of these commands deploys artifacts.
They keep `target/` for incremental builds. Use `mvn clean` only when stale
outputs are a possible cause. Cold dependency downloads take longer than a warm
build. No fixed build duration is guaranteed.

`sbom` records the resolved dependency graph in CycloneDX files under `target/`.
CI retains these files with the build output. Maven uses strict checksum checks,
but this is not a content lock for every transitive artifact. Dependency review
rejects new high and critical advisories when GitHub dependency review is enabled.
`reproduce` makes two clean packages of one module and compares their bytes. It
uses the commit time for archive timestamps and the inherited `Build-Time`
manifest field. It skips tests, so run tests separately first. A local match does
not guarantee that signing or publishing produces identical bytes.

The command writes its duration, exit status, and command to `target/agent/`.
It fails if Maven changes a tracked file. Read the first Maven `ERROR` and the
module's `target/surefire-reports/` after a test failure. Preserve the failing
sample, exact command, JDK, and revision. Do not rerun until green without
recording and correcting the cause. `repeat` runs a selected suite twice and
stops at the first failure. It is a local flake check, not proof of determinism.

## Follow the source contracts

Use two spaces in Java and XML, and four spaces in Python. Use the existing
package names and `*Test` class names. Keep imports explicit. Match package
directories. `scripts/dev.py check` rejects reactor cycles, undeclared local
source imports, package-directory errors, and added whitespace errors. It also
runs the command-tool tests. `.editorconfig` gives editor defaults. Test resources
can contain deliberate invalid source and whitespace; do not format them.
Use `check --base <ref>` to include committed changes in whitespace and
credential checks. CI supplies the PR base explicitly. With no base, the tool
checks local changes from `HEAD`.
To run these fast checks before a commit, opt in with
`git config --local core.hooksPath .githooks`. This is a repository-local setting;
the setup command does not change global Git configuration. The same checks run
in CI even when the local hook is not enabled.

New public APIs affect many analyzers. Prefer the existing API and a small
implementation change. Keep `internal` implementation classes behind their
public entry points. Preserve package null contracts from `package-info.java`.
Do not add a dependency to a shared library without checking its consumers and
JAR size. Compiler checks and tests check types; NEXT analysis supplies broader
null, dead-code, duplication, and size feedback. Do not claim that the local
checks replace this analysis.

`quality` produces local PMD and duplicate-code reports under each selected
module's `target/site/`. It supplies feedback for unused private code, class
names, large classes/methods, and duplicated token blocks. These reports are
not a new merge gate, and they do not prove null safety or API compatibility.
The VS Code extension recommendations enable EditorConfig and SonarQube for IDE
when installed. CI's `coverage` profile also checks a 60% line-coverage floor in
each module with measured code. A coverage floor does not prove that assertions
are useful; keep behavior assertions and counterexamples in the tests.

Start a new Java test from a small adjacent test. `CodeRecognizerTest` is a
simple JUnit 4 example. `EmptyGroupFinderTest` and its YAML file show the regex
finder pattern. Some modules use JUnit 4 and others use JUnit Jupiter; preserve
the module's dependency choice. Include a positive case, a negative case, and
relevant boundaries. Assert actual output and locations. Do not weaken expected
results to obtain a passing test. No generated test scaffold is required.

## Keep changes bounded

Work on a side branch. Use `fix/`, `feat/`, or `chore/` with a short description.
Use an `ACOMMONS-<number>` prefix in the commit and PR title when a ticket exists;
otherwise use a conventional title such as `chore: Improve local checks`.
Separate behavior changes from broad formatting or dependency updates. Keep
each PR small enough to explain and test. The readiness workflow checks the
title and reports changed line counts. Its size limit requires a maintainer's
`large-change-reviewed` label for an exceptional PR.

Before completion, run the affected module suites, `python3 scripts/dev.py
verify`, and inspect the full diff. Required CI and NEXT checks must pass before
merge. A local pass does not establish downstream compatibility or a green CI
result. If an API or common parser changes, identify affected consumers in the
PR. Do not merge, tag, sign, release, promote, publish, or force-push unless the
user explicitly requests that operation. CI performs those operations under its
own permissions. Never use release credentials for local tests.

## Edit the source of generated data

Do not commit `target/`, `dependency-reduced-pom.xml`, generated configuration
JSON, or generated npm/NuGet archives. Configuration JSON comes from
`SecretClassifier` and the exporter classes. Change those sources, then run
configuration-module tests and package verification. Packaging templates under
`sonar-analyzer-commons-configurations/src/main/packaging/` are source files;
their filtered copies under `target/packaging/` are generated.

The verifier corpus under `test-commons/src/test/resources/`, and regex finder
YAML files, are deliberate test data. Edit them only to test a stated behavior.
Rule JSON and HTML under `commons/src/test/resources/` are loader test fixtures,
not production rule descriptions. Do not regenerate all expected data for an
unrelated change. Marketing owns the marked root README section and logo URLs.

Use network access for required dependency resolution and source references.
Do not send repository source, test corpora, credentials, or build logs to an
external service unless the task authorizes that service. Repository checks
scan added lines for selected credential formats; they cannot detect every
secret. Stop and remove a real credential if one is found, then follow the
organization's credential-rotation process.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,32 @@ To learn more about the SonarQube product family, visit the [Sonar website](http
## Modules

* [commons](commons) Logic useful for a language plugin
* [sonar-analyzer-commons-configurations](sonar-analyzer-commons-configurations) JSON, npm, and NuGet exports of shared configuration
* [recognizers](recognizers) Logic useful for detecting commented out code
* [test-commons](test-commons) Logic useful to test a language analyzer
* [xml-parsing](xml-parsing) Logic useful to analyze and test checks for XML file
* [test-xml-parsing](test-xml-parsing) Logic useful to test XML parsing and XML-related rules
* [regex-parsing](regex-parsing) Logic used to parse regular expressions (currently only for Java)
* [regex-parsing](regex-parsing) Regular-expression parsing and shared checks, with Java, PHP, and Python source adapters
* [performance-measure](performance-measure) Nested duration measurements and report merging

## Build
Use JDK 21 and Maven 3.9.16. [mise.toml](mise.toml) pins both tools.
Python 3.9 or later runs the local command tool.

```sh
mise trust
mise install
python3 scripts/dev.py doctor --resolve
python3 scripts/dev.py verify
```
mvn clean install
```

For a quick module test, run `python3 scripts/dev.py test recognizers`.
For a full local install, run `python3 scripts/dev.py build`.
These commands retain build outputs for incremental work and never publish.
See [AGENTS.md](AGENTS.md) for module selection, failure diagnosis, source
boundaries, and contribution rules. The optional [.devcontainer](.devcontainer)
contains a development environment. CI signing and publishing require internal
services; local unit tests do not require them.

### License
Copyright 2009-2023 SonarSource.
Expand Down
23 changes: 23 additions & 0 deletions commons/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Common analyzer utilities

Production code is under `src/main/java/org/sonarsource/analyzer/commons/`.
Tests mirror that package under `src/test/java/`. Start with `TokenLocation`
and `TokenLocationTest` for a small utility and its output assertions.

`RuleMetadataLoader` combines annotations with JSON/HTML rule resources.
`BuiltInQualityProfileJsonLoader` loads profile definitions. Their test resources
contain deliberately invalid and historical data. Change a resource only when
the loader behavior under test requires it.

`appsec/` contains IP, protocol, key-size, test-file, and secret classification.
Secret configuration exports consume `SecretClassifier` from the configurations
module. A classifier change therefore requires both module suites and a package
verification. `collections/` contains persistent collection helpers. Preserve
their immutability and iterator contracts.

The POM relocates `org.json.simple` into an internal namespace during shading.
Do not expose that shaded package in a public API. `verify` checks the existing
JAR size limit. New dependencies increase the size of many analyzers.

From the root, run `python3 scripts/dev.py test commons`. A change to a public
utility also needs a check of affected analyzer callers outside this repository.
6 changes: 5 additions & 1 deletion commons/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
SonarSource Analyzers Commons (compatible with SQ >=7.9)
SonarSource Analyzers Commons
=========================
Logic useful for an average language plugin

The plugin API version is set in the root POM. Check an analyzer's supported
SonarQube versions before updating this dependency. See [AGENTS.md](AGENTS.md)
for source locations and tests.

* [`RuleMetadataLoader`](./src/main/java/org/sonarsource/analyzer/commons/RuleMetadataLoader.java) - to define rules metadata based on `json` and `html` files, or, when constructed without a resource folder, directly from the `org.sonar.check.Rule` annotation
* [`DeprecatedRuleKey`](./src/main/java/org/sonarsource/analyzer/commons/annotations/DeprecatedRuleKey.java) annotation - when used with [`RuleMetadataLoader`](./src/main/java/org/sonarsource/analyzer/commons/RuleMetadataLoader.java) in will add deprecated rule key for an annotated rule
* [`BuiltInQualityProfileJsonLoader`](./src/main/java/org/sonarsource/analyzer/commons/BuiltInQualityProfileJsonLoader.java) - to define default rules profiles based on `json` file
Expand Down
17 changes: 17 additions & 0 deletions config/pmd.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Local source feedback"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>Local feedback for unused code, naming, and source reading size.</description>
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
<rule ref="category/java/codestyle.xml/ClassNamingConventions"/>
<rule ref="category/java/design.xml/NcssCount">
<properties>
<property name="classReportLevel" value="1000"/>
<property name="methodReportLevel" value="100"/>
</properties>
</rule>
</ruleset>
4 changes: 2 additions & 2 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[tools]
java = "21.0"
maven = "3.9"
java = "corretto-21.0.11.10.1"
maven = "3.9.16"
13 changes: 13 additions & 0 deletions performance-measure/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Performance measurements

`PerformanceMeasure` starts and stops nested duration measurements.
`DurationMeasure` stores the hierarchy. `DurationMeasureFiles` reads and writes
reports. `DurationMeasureMerger` combines measurements. `log/` adapts logging.
The README shows the sensor and report flow.

Preserve disabled-mode behavior, nesting, thread behavior, and report format.
Do not make correctness tests depend on a fixed wall-clock duration. Use the
adjacent measurement and merger tests for the behavior under change.

Run `python3 scripts/dev.py test performance-measure` from the root. No running
SonarQube service is needed for these unit tests.
Loading
Loading