↑ ↓ para mover · Enter para abrir · Esc para fecharToque em um resultado

Arquitetura
skill · classe build · sonnet

sonarqube-setup

Liga o projeto a um servidor SonarQube: o scanner no arquivo de build e um passo de CI ou um container local.

skill · buildsonneteffort low3 caminhos permitidosvai para o projeto gerado
§ a definição da skill

sonarqube-setup, seção a seção

As seções do próprio SKILL.md da skill, em trechos. Passe o mouse ou clique numa delas para ver quais regras do projeto, templates e arquivos de references/ ela cita. As seções também são chips: clique num para ir até ela.

nerviz/.claude/skills/sonarqube-setup/SKILL.md

## Why this is a skill (Form 1) and not Form 2

Form 1: project-bootstrap and arch-adopt chain it by name, and a skill with disable-model-invocation: true cannot be called through the Skill tool — the same reason git-publish and docker-architect stay model-invocable. Axis 2 of the interview — two callers, one of which runs inside a project where project-bootstrap does not exist — is what made it a skill of its own instead of a step inside the bootstrap. The closest rejected form was that step: arch-adopt would then have to write pom.xml and docker-compose.yml itself, widening its territory and giving the compose file a second owner. Record: @.claude/decisions/0091-sonarqube-setup-skill.md.

Runs on sonnet with effort: low: a fixed procedure behind one question, every version resolved by curl (@.claude/decisions/0080-procedural-skills-on-sonnet.md).

## Procedure

Project directory. When the caller's one-line context names project: <absolute path>, that directory is the project root, not the session's: read and write every path of this procedure under it, and run every shell command as (cd "<path>" && …). When this skill chains docker-architect, pass project: <path> on in its context.

### 1 · Detect the build tool and whether Sonar is already there

pom.xml at the root → maven. build.gradle at the root → gradle. Neither → stop: there is no project to configure. Both → stop and say so; this repo never generates both.

Grep the root build file for sonar-maven-plugin / org.sonarqube. Found → entry rule above: report and stop.

### 2 · Ask about the server — one `AskUserQuestion`

Two questions in the same call:

  1. Server — "Is there already a SonarQube server or SonarCloud organization for this
  2. Authentication — "How does the analysis authenticate?"

When a caller already passed an answer in its one-line context, don't ask it again.

### 3 · Write the build configuration

Resolve the scanner version on the repository itself — never from memory, same rule project-bootstrap/references/build-maven.md § 4.6 applies to every plugin:

# maven
curl -sS 'https://repo1.maven.org/maven2/org/sonarsource/scanner/maven/sonar-maven-plugin/maven-metadata.xml' | grep -o '<release>[^<]*</release>'
# gradle — the plugin lives on the Gradle Plugin Portal, not on Maven Central
curl -sS 'https://plugins.gradle.org/m2/org/sonarqube/org.sonarqube.gradle.plugin/maven-metadata.xml' | grep -o '<release>[^<]*</release>'

No network → don't write a version: say which one could not be resolved and let the user supply it.

Then merge — never replace what the root build file already has:

ToolExemplarWhere
maventemplates/pom-sonar.xml.exampleproperties into the root POM's <properties>, the plugin into <build><pluginManagement><plugins>
gradletemplates/build-gradle-sonar.examplethe plugin into the root plugins {}, the sonar {} block at the root level — not inside subprojects

sonar.projectKey is <groupId>:<artifactId> from the root build file. sonar.host.url is the URL from step 2, or http://localhost:9000 for the local container. sonar.organization only for SonarCloud. The coverage report path needs no property: the scanner's default report paths are exactly where the JaCoCo setup project-bootstrap writes puts them (target/site/jacoco/jacoco.xml, build/reports/jacoco/test/jacocoTestReport.xml).

… cortado aqui, o resto está no arquivo

### 4 · Local server — only when step 2 answered *None*

Invoke docker-architect through the Skill tool with a one-line context: "service sonarqube, chained from sonarqube-setup — no engine question". It owns every service block in docker-compose.yml, and its template for this one is templates/sonarqube-service.yml.example there. Don't write the block here, not even when it looks like a copy: that is the ownership split, not a style choice.

No docker-compose.yml at the root → docker-architect stops on its own entry rule. Report that the build points at http://localhost:9000 and nothing runs there yet.

### 5 · CI — only when the server is external

A local container is unreachable from a CI runner, so this step runs only for an existing server or SonarCloud. Merge templates/ci-sonar-step.yml.example into .github/workflows/build.yml (the file project-bootstrap step 6.5 writes): job-level env, fetch-depth: 0 on the checkout, and the analysis step after verify. The step is skipped while the SONAR_TOKEN secret is absent — a fork's pull request has none, and a red build there would say nothing about the code.

No .github/workflows/build.yml → skip, and say it in the report.

## Report

✅ SonarQube configured — <existing server <url> | SonarCloud <org> | local container>

Build ....... <pom.xml | build.gradle> — scanner <version> (resolved from <repository>)
Project key . <groupId:artifactId>
Coverage .... sonar.coverage.exclusions = <patterns> (from the JaCoCo excludes in <file>:<line>) | not set — no JaCoCo excludes in <file>
Server ...... <url> · auth: <SONAR_TOKEN | anonymous>
Compose ..... <sonarqube added by docker-architect, tag <tag> | not touched — external server>
CI .......... <step added, runs when secret SONAR_TOKEN is set | skipped — local server | skipped — no workflow>

Access check (before any scan):
  curl -s <url>/api/authentication/validate      → {"valid":true} when anonymous is allowed
  (or SONAR_TOKEN is exported — the scanner reads it)

First run:  <./mvnw -B verify sonar:sonar | ./gradlew build sonar>
Rerun:      <./mvnw -B sonar:sonar | ./gradlew sonar>   — same build output, no tests again

The access check moves an authentication failure from the end of the scan to its start: validate answers in milliseconds, the scan fails only after verify has run every test. The rerun line is for a change on the server side — a setting, a permission, a quality profile — where the code and target/ (or build/) are unchanged.

… cortado aqui, o resto está no arquivo

Abrir o arquivo completo no GitHub →
§ comportamento

O que lê, escreve e recusa

O contrato da própria skill, do SKILL.md, no texto original.

Class

build — the territory is skill_classes.build's override for this skill in @.claude/schemas/extensions.json: the root build file and .github/workflows/**, nothing else. ArchHook.java guard enforces it. docker-compose.yml is deliberately outside it.

Reads

the root pom.xml or build.gradle (coordinates, existing plugins, the JaCoCo excludes that sonar.coverage.exclusions is derived from), and .github/workflows/build.yml when it exists.

Writes

the scanner plugin and the sonar.* properties into the root build file — the only change to that file outside a feature round besides project-bootstrap's generation and the two installers' own setup — and the analysis step into the workflow when the server is external.

Never writes

a token, a password, or any credential value, in any file.

Delegates

the sonarqube compose service to docker-architect, the single owner of every service block.

Chained by

project-bootstrap (step 8.4, after Verify) and arch-adopt (step 7), and invocable by hand. Travels into the generated project (export.skills.include): arch-adopt runs inside the project, where project-bootstrap does not exist, and needs this skill there.

Fonte: SKILL.md § Contract, no nerviz e4cae27.

§ guard e hook

O que o guard faz com ela

build é a classe da skill, e cada skill dela tem território próprio. Quem chama decide qual território vale: sob o project-initializer, o do agent; da thread principal, nenhuma chamada passa. O texto à direita é o do próprio hook.

write_allow da classe sonarqube-setup

  • ✓pom.xml
  • ✓build.gradle
  • ✓.github/workflows/**
  • qualquer caminho fora desta lista, quando a própria skill abre a fase
  • uma chamada da thread principal com o /init-project aberto

A recusa sai com código 2 e a mensagem volta para o modelo.

Encadeada pelo project-initializer, as escritas dela levam o agent_type do agent e são julgadas por agent_classes.driver, **. Esta lista vale quando a skill roda num prompt próprio.

PreToolUse  Skill(sonarqube-setup)
# agent_type: project-initializer (class driver)
  guard call                       exit 0
# a classed agent's call leaves the phase as it was
PreToolUse  Write(../bank-app/pom.xml)
  guard write                      exit 0
# judged by agent_classes.driver, write_allow: **
§ orquestração

Onde ela fica no trilho

Cada card é um passo do /init-project. A entrevista roda na sessão principal; os passos com fundo colorido rodam dentro do project-initializer; o git-publish volta para a sessão principal, depois do audit genesis. Passos tracejados só rodam quando se aplicam.

← voltar às cadeias