Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 0 additions & 24 deletions .claude-plugin/marketplace.json

This file was deleted.

51 changes: 31 additions & 20 deletions .github/workflows/parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ name: Scan parity (self-scan ↔ SonarQube Cloud)
# Runs BOTH scans on the same commit and diffs their issue lists. Every PR
# answers: "does our daemon find what SonarSource's own pipeline finds?".
#
# This workflow supersedes .github/workflows/sonarqube-cloud.yml — that file
# was removed in the same commit; the Cloud scan now happens here, alongside
# the self-scan and the parity comparison. The standalone self-scan
# (sonar.yml) is kept because it works on fork PRs (no SONAR_TOKEN needed),
# whereas this one requires the token and so skips for forks.
# The standalone self-scan (sonar.yml) is kept because it works on fork PRs
# (no SONAR_TOKEN needed), whereas this one requires the token and so skips
# for forks.
#
# Setup required (one-time, by the repo admin):
# 1. Sign in to https://sonarcloud.io with the repo's GitHub org.
Expand Down Expand Up @@ -41,8 +39,9 @@ jobs:
# self-scan workflow still gates fork PRs on our daemon's findings.
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
env:
# Same dist-assembly heap concern as sonar.yml — 2 GB to keep the
# 150 MB skill-bundle zip step from OOMing maven-assembly-plugin.
# The assembly step packages the ~150 MB distribution bundle (CLI +
# daemon fat jars + 10 analyzer plugins). 2 GB heap keeps maven-assembly-plugin
# from OOMing while it zips the bundle.
MAVEN_OPTS: -Xmx2g
steps:
- name: Checkout
Expand Down Expand Up @@ -89,24 +88,36 @@ jobs:
fi
echo "SONAR_TOKEN configured."

# Single build that both scans then consume. `verify` also produces
# the per-module JaCoCo XMLs that both scans use as coverage evidence.
- name: Build and test (generates JaCoCo XML)
run: mvn -B -ntp -pl '!dist' verify -Dsurefire.failIfNoSpecifiedTests=false
# Single build that both scans then consume. `verify` produces the
# JaCoCo XML that both scans use as coverage evidence, plus the
# distribution bundle the self-scan invokes via its bin/sonar launcher.
- name: Build and test (generates JaCoCo XML + distribution bundle)
run: mvn -B -ntp clean verify -Dsurefire.failIfNoSpecifiedTests=false

- name: Build dist (skill bundle for self-scan)
run: mvn -B -ntp -pl dist -am package -DskipTests
# Derive the project version from pom.xml so SONAR_PREDICTOR_HOME below
# tracks pom bumps without anyone touching CI.
- name: Derive project version
id: version
run: |
set -euo pipefail
VERSION=$(mvn -B -ntp -q -DforceStdout help:evaluate -Dexpression=project.version)
if [ -z "${VERSION}" ]; then
echo "::error::could not derive project.version from pom.xml"
exit 1
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "Project version: ${VERSION}"

# --- (A) Self-scan ------------------------------------------------------

- name: Run self-scan
run: |
set +e
export SONAR_PREDICTOR_HOME="$(pwd)/dist/target/skill/sonar-predictor"
./plugin/skills/sonar-predictor/bin/sonar agent-scan analyze . \
--coverage protocol/target/site/jacoco/jacoco.xml \
--coverage daemon/target/site/jacoco/jacoco.xml \
--coverage cli/target/site/jacoco/jacoco.xml
export SONAR_PREDICTOR_HOME="$(pwd)/target/sonar-predictor-dist-${{ steps.version.outputs.version }}/sonar-predictor"
mkdir -p .sonar-predictor
"$SONAR_PREDICTOR_HOME/bin/sonar" \
--format json --save .sonar-predictor/scan.json \
analyze . --coverage target/site/jacoco/jacoco.xml
rc=$?
set -e
echo "Self-scan exit code: $rc (0=clean, 1=issues found, 2+=tool error)"
Expand All @@ -122,13 +133,13 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mvn -B -ntp -pl '!dist' \
mvn -B -ntp \
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
-Dsonar.projectKey="${SONAR_PROJECT_KEY}" \
-Dsonar.organization="${SONAR_ORGANIZATION}" \
-Dsonar.host.url="${SONAR_HOST_URL}" \
-Dsonar.qualitygate.wait=false \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../protocol/target/site/jacoco/jacoco.xml,../daemon/target/site/jacoco/jacoco.xml,../cli/target/site/jacoco/jacoco.xml
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml

# SonarQube Cloud processes the scan asynchronously after upload. Poll
# the last completed analysis until the timestamp moves past the start
Expand Down
63 changes: 21 additions & 42 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ name: Publish to Maven Central + GitHub Release
# from the Actions tab with an explicit version.
#
# On a run it:
# 1. derives the release version from the tag (v0.1.0 -> 0.1.0) — Maven
# 1. derives the release version from the tag (v0.2.0 -> 0.2.0) — Maven
# Central rejects -SNAPSHOT, so versions:set strips it,
# 2. builds, tests, GPG-signs and deploys protocol/daemon/cli to Maven
# Central via the Sonatype Central Portal (the dist module sets
# maven.deploy.skip=true so it is built but never staged),
# 3. creates a GitHub Release carrying two bundles: a whole-repo source
# zip (git archive of HEAD) and the assembled skill bundle zip. The
# plugin itself is installed via the in-repo /plugin/ directory through
# Claude Code's / Copilot CLI's marketplace (see /.claude-plugin/
# marketplace.json); its skill launcher downloads the analyzer bundle
# on first run from the Maven Central artifact this workflow publishes.
# 2. builds, tests, GPG-signs and deploys the parent pom + attached source
# zip + attached distribution zip to Maven Central via the Sonatype
# Central Portal. This is a single-module project with packaging=pom;
# its deploy attaches: parent pom + source zip (classifier=src) + dist
# zip (classifier=dist). No daemon/cli JARs are published to Central,
# 3. creates a GitHub Release carrying two assets: a whole-repo source
# zip (git archive of HEAD) and the assembled distribution bundle
# (sonar-predictor-dist-<version>.zip — bin/sonar{,.bat} + lib/*.jar +
# plugins/*.jar). Users install by downloading + extracting the zip.
#
# Required repo secrets:
# OSS_NEXUS_USER - Sonatype Central Portal token username
Expand All @@ -30,7 +30,7 @@ on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g. 0.1.0) — required for manual runs'
description: 'Release version (e.g. 0.2.0) — required for manual runs'
required: true
type: string

Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
if [ -n "${INPUT_VERSION:-}" ]; then
VERSION="${INPUT_VERSION}"
else
# github.ref_name is the tag, e.g. v0.1.0 -> 0.1.0
# github.ref_name is the tag, e.g. v0.2.0 -> 0.2.0
VERSION="${GITHUB_REF_NAME#v}"
fi
if [ -z "${VERSION}" ]; then
Expand All @@ -92,18 +92,6 @@ jobs:
-DnewVersion="${{ steps.version.outputs.version }}" \
-DgenerateBackupPoms=false

- name: Sync skill bundle version pin to the release version
# The skill launcher reads SONAR_BUNDLE_VERSION from config.env to
# decide which sonar-predictor-dist-<version>.zip to fetch from
# Maven Central on first invocation. If config.env is stale, an
# installed plugin downloads the wrong bundle. Forcing the pin to
# match the tag here removes that trap from every future release.
run: |
set -euo pipefail
CONFIG=plugin/skills/sonar-predictor/config.env
sed -i "s|^SONAR_BUNDLE_VERSION=.*|SONAR_BUNDLE_VERSION=${{ steps.version.outputs.version }}|" "${CONFIG}"
grep '^SONAR_BUNDLE_VERSION' "${CONFIG}"

- name: Build the source bundle (whole-repo git archive of HEAD)
# Built BEFORE the deploy: the release profile's build-helper plugin
# attaches this zip (from the repo root) to the Maven Central upload,
Expand All @@ -124,21 +112,7 @@ jobs:
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
run: |
set -euo pipefail
mvn -B -ntp -Prelease deploy

- name: Locate the skill bundle zip
id: bundle
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
SKILL_ZIP="dist/target/sonar-predict-skill-${VERSION}.zip"
if [ ! -f "${SKILL_ZIP}" ]; then
echo "::error::skill bundle not found at ${SKILL_ZIP}"
ls -la dist/target || true
exit 1
fi
echo "skill_zip=${SKILL_ZIP}" >> "$GITHUB_OUTPUT"
echo "Skill bundle: ${SKILL_ZIP}"
mvn -B -ntp -Prelease clean deploy

- name: Create the GitHub Release
env:
Expand All @@ -147,14 +121,19 @@ jobs:
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
SRC_ZIP="sonar-predict-${VERSION}-src.zip"
SKILL_ZIP="${{ steps.bundle.outputs.skill_zip }}"
DIST_ZIP="target/sonar-predictor-dist-${VERSION}.zip"
if [ ! -f "${DIST_ZIP}" ]; then
echo "::error::distribution bundle not found at ${DIST_ZIP}"
ls -la target || true
exit 1
fi
if [ -n "${GITHUB_REF_NAME:-}" ] && [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
TAG="${GITHUB_REF_NAME}"
else
TAG="v${VERSION}"
fi
gh release create "${TAG}" \
--title "sonar-predict ${VERSION}" \
--title "sonar-predictor ${VERSION}" \
--generate-notes \
"${SRC_ZIP}" \
"${SKILL_ZIP}"
"${DIST_ZIP}"
72 changes: 39 additions & 33 deletions .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ permissions:
# passes through the same gate, so the bar we apply to others applies to us.
#
# We deliberately do NOT use the previously released bundle from Maven Central.
# SONAR_PREDICTOR_HOME is repointed at dist/target/skill/sonar-predictor so the
# scan exercises the branch's analyzer code, not yesterday's release.
# SONAR_PREDICTOR_HOME is repointed at the freshly-built exploded distribution
# under target/ so the scan exercises this branch's analyzer code, not
# yesterday's release.

on:
pull_request:
Expand All @@ -24,11 +25,11 @@ jobs:
name: Self-scan
runs-on: ubuntu-latest
env:
# The dist-assembly step packages the ~150 MB skill bundle (CLI + daemon
# fat jars + 10 analyzer plugins). Maven's default heap is too small for
# that on ubuntu-latest — we'd get 'Execution exception: Java heap space'
# from maven-assembly-plugin:single. 2 GB is plenty and well under the
# runner's ~7 GB available memory.
# The assembly step packages the ~150 MB distribution bundle (CLI +
# daemon fat jars + 10 analyzer plugins). Maven's default heap is too
# small for that on ubuntu-latest — we'd get 'Execution exception:
# Java heap space' from maven-assembly-plugin:single. 2 GB is plenty
# and well under the runner's ~7 GB available memory.
MAVEN_OPTS: -Xmx2g
steps:
# fetch-depth: 0 keeps the full history available so we can switch to
Expand All @@ -52,9 +53,9 @@ jobs:
with:
node-version: '20'

# Cache the local Maven repo across runs. Keyed on every pom.xml in the
# tree so a dependency change invalidates cleanly; restore-keys lets a
# partial cache hit still seed most of ~/.m2.
# Cache the local Maven repo across runs. Keyed on the pom.xml so a
# dependency change invalidates cleanly; restore-keys lets a partial
# cache hit still seed most of ~/.m2.
- name: Cache Maven repository
uses: actions/cache@v4
with:
Expand All @@ -63,26 +64,31 @@ jobs:
restore-keys: |
${{ runner.os }}-maven-

# Build + test the whole reactor except `dist` (the bundle module is
# packaged separately below). `verify` runs the integration tests AND
# produces the JaCoCo XML reports we feed back into the scan as coverage
# evidence. failIfNoSpecifiedTests=false keeps modules with no tests
# from breaking the reactor.
- name: Build and test (generates JaCoCo XML reports)
run: mvn -B -ntp -pl '!dist' verify -Dsurefire.failIfNoSpecifiedTests=false
# Single-module build. `verify` runs the integration tests AND produces
# the JaCoCo XML report we feed back into the scan as coverage evidence,
# plus the distribution bundle the self-scan invokes below.
- name: Build and test (generates JaCoCo XML + distribution bundle)
run: mvn -B -ntp -Dmaven.test.skip=false clean verify -Dsurefire.failIfNoSpecifiedTests=false

# Now build the skill bundle. -am pulls in upstream modules if they
# weren't already installed by the previous step. -DskipTests because
# the tests already ran — re-running them here just wastes minutes.
- name: Build dist (skill bundle this scan will use)
run: mvn -B -ntp -pl dist -am package -DskipTests
# Derive the project version from pom.xml so SONAR_PREDICTOR_HOME below
# tracks pom bumps without anyone touching CI.
- name: Derive project version
id: version
run: |
set -euo pipefail
VERSION=$(mvn -B -ntp -q -DforceStdout help:evaluate -Dexpression=project.version)
if [ -z "${VERSION}" ]; then
echo "::error::could not derive project.version from pom.xml"
exit 1
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "Project version: ${VERSION}"

# The actual self-scan. We override SONAR_PREDICTOR_HOME so the wrapper
# script picks up THIS branch's freshly-built daemon jar and analyzer
# plugins, not whatever happens to be installed globally. Three JaCoCo
# XMLs are passed in as coverage evidence — one per Java module that
# produces coverage. agent-scan writes JSON to .sonar-predictor/scan.json
# and prints a human summary on stdout; we want both.
# The actual self-scan. We point bin/sonar at THIS branch's
# freshly-built distribution under target/ (not whatever happens to
# be installed globally), and capture the scan as JSON to
# .sonar-predictor/scan.json via --save. One JaCoCo XML is passed
# in as coverage evidence (single module = one report).
#
# IMPORTANT: the CLI uses three-state exit codes
# 0 = clean (no findings at the floor)
Expand All @@ -95,11 +101,11 @@ jobs:
- name: Run self-scan
run: |
set +e
export SONAR_PREDICTOR_HOME="$(pwd)/dist/target/skill/sonar-predictor"
./plugin/skills/sonar-predictor/bin/sonar agent-scan analyze . \
--coverage protocol/target/site/jacoco/jacoco.xml \
--coverage daemon/target/site/jacoco/jacoco.xml \
--coverage cli/target/site/jacoco/jacoco.xml
export SONAR_PREDICTOR_HOME="$(pwd)/target/sonar-predictor-dist-${{ steps.version.outputs.version }}/sonar-predictor"
mkdir -p .sonar-predictor
"$SONAR_PREDICTOR_HOME/bin/sonar" \
--format json --save .sonar-predictor/scan.json \
analyze . --coverage target/site/jacoco/jacoco.xml
rc=$?
set -e
echo "Self-scan exit code: $rc (0=clean, 1=issues found, 2+=tool error)"
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependency-reduced-pom.xml
# Analyzer plugin JARs (~160 MB) dropped here for dev runs of the daemon
# module. Not committed to keep the repo lean. The distribution build (dist
# module) fetches its own copies through Maven and does not use this directory.
daemon/plugins/*.jar
plugins/*.jar

# sonar-predictor scan output, written by `bin/sonar agent-scan`. Never commit.
.sonar-predictor/
Expand Down
Loading
Loading