Lo scopo di questa guida è quello di fornire i passaggi dettagliati per la configurazione del repository per l’utilizzo di Sonarqube in vista dei tutorati.

La guida è rivolta agli studenti della prova finale di Ingegneria del Software, AA 2021-2022.

Cos’è SonarQube?

SonarQube è uno strumento che consente ad un team di scrivere codice più pulito e più sicuro. Esso garantisce unʼispezione continua del codice e mette a disposizione migliaia di regole automatizzate finalizzate all’analisi statica del codice. Queste regole forniscono protezione al progetto esaminato e guidano il team di sviluppo.

Maggiori dettagli

Il primo step è quello di configurare correttamente il proprio progetto Maven per consentire l’upload del report sul server remoto.

Configurazione pom.xml

Prima di tutto sarà necessario aprire il file pom.xml ed apportare le modifiche di seguito descritte.

Configurazione artifactId

Nella sezione iniziale del pom sarà necessario impostare l’artifact id correttamente, inserendo il nome del proprio gruppo (es. AM01)

<artifactId>NOME-GRUPPO</artifactId>

Installazione plugin sonar scanner

Dopo aver sistemato l’artifactId, sarà necessario copiare e incollare questo frammento nella sezione del file pom.xml

<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
    <version>3.7.0.1746</version>
</plugin>

Installazione plugin Jacoco

Dopo aver installato il plugin di sonar scanner allo step precedente, sarà necessario copiare e incollare questo frammento nella sezione del file pom.xml

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.7</version>
    <configuration>
      <excludes>
      </excludes>
    </configuration>
    <executions>
      <execution>
        <id>default-prepare-agent</id>
        <goals>
          <goal>prepare-agent</goal>
        </goals>
      </execution>
      <execution>
        <id>jacoco-report</id>
        <phase>test</phase>
        <goals>
          <goal>report</goal>
        </goals>
      </execution>
    </executions>
</plugin>

Una volta terminata la configurazione, la struttura del vostro file pom.xml dovrebbe essere molto simile alla seguente:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <!-- TEST VALUES, DO NOT COPY -->
  <groupId>it.polimi.ingsw</groupId>
  <artifactId>AM00</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>AM00</name>
  <url>http://lucapirovano.dev</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <sonar.exclusions>**/TestClass.java</sonar.exclusions>
  </properties>

  <dependencies>
    ...
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    ...
  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        ...
        <plugin>
          <groupId>org.sonarsource.scanner.maven</groupId>
          <artifactId>sonar-maven-plugin</artifactId>
          <version>3.7.0.1746</version>
        </plugin>
        ...
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>17</source>
          <target>17</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.7</version>
        <configuration>
          <excludes>
          </excludes>
        </configuration>
        <executions>
          <execution>
            <id>default-prepare-agent</id>
            <goals>
              <goal>prepare-agent</goal>
            </goals>
          </execution>
          <execution>
            <id>jacoco-report</id>
            <phase>test</phase>
            <goals>
              <goal>report</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Configurazione GitHub action

Lo step successivo è quello di configurare una GitHub action che permetta di caricare automaticamente il report del codice su Sonarqube.

Se volete sapere cosa sono le GitHub actions, potete leggere la documentazione ufficiale.

Ai fini del corso, sarà sufficiente seguire i passaggi di seguito indicati:

  • nella root del progetto create la cartella .github ed entrate in essa (sì, con il punto all’inizio!);
  • all’interno della cartella createne una nuova, chiamata workflows ed entrate in essa;
  • all’interno di workflows create un file chiamato report.yml
  • copiate e incollate il seguente snippet all’interno del file report.yml.
name: Build
on:
  schedule:
    - cron: '00 02,18 * * *'
    - cron: '00 10 * * 2'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17
      - name: Cache SonarQube packages
        uses: actions/cache@v1
        with:
          path: ~/.sonar/cache
          key: ${{ runner.os }}-sonar
          restore-keys: ${{ runner.os }}-sonar
      - name: Cache Maven packages
        uses: actions/cache@v1
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2
      - name: Build and analyze
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=${{ secrets.REPOSITORY_OWNER }}_${{ secrets.REPOSITORY_NAME }}

** IMPORTANTE **: se utilizzate una versione di java diversa dalla 17, dovrete inserirla nel campo java-version.

Configurazione repository GitHub

Una volta configurato correttamente il progetto maven e il file action, potrete procedere alla configurazione del repository.

Dal sito github.com, accedete al vostro repository e navigate su
Settings->Security->Secrets->Actions.

Verrà mostrata una schermata simile a questa
GitHub secrets

Dovrete aggiungere i seguenti 4 valori, cliccando ogni volta su New repository secret:

  • REPOSITORY_NAME: il nome della vostra repository su GitHub (ingsw2022-AMxx oppure ingsw-2022-cognome1-cognome2-cognome3, etc)
  • REPOSITORY_OWNER: il nickname di github dello studente che ha creato la repository (es. PiroX4256)
  • SONAR_HOST_URL: la URL comunicata tramite WeBeep
  • SONAR_TOKEN: il token comunicato tramite WeBeep

La action è programmata per eseguire due analisi:

  • alle ore 02:00 e 18:00 di ogni giorno
  • alle ore 12:00 di ogni martedì, prima del tutorato.

Per questo motivo, è FONDAMENTALE che sul branch master della repository sia SEMPRE presente codice funzionante e che compila correttamente.

Il branch da cui SonarQube effettuerà l’analisi del codice è soltanto master (main), quindi accertatevi sempre che i merge su quel branch siano aggiornati, altrimenti vedremo report di codice vecchio.

Aggiunta Esclusioni Coverage

Siccome verranno elaborate le metriche relative alla code coverage dei test, vi chiediamo di escludere tutte le classi e i packages (ovvero le vostre subdirectories) che non sono richieste per il corso.

Ricordiamo infatti che i test andranno scritti su tutto il model e sul controller, e che la code coverage globale deve essere almeno dell’80%.

Potete verificare in ogni momento il valore della coverage da IntelliJ, cliccando con il tasto destro sulla cartella contenente i test e selezionando “Run with coverage”.

Per aggiungere un’esclusione dal code coverage report, dovrete modificare il vostro pom.xml, nella sezione properties, posta all’inizio del file, che dovrebbe essere simile a questa:

...
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>17</maven.compiler.source>
  <maven.compiler.target>17</maven.compiler.target>
</properties>
...

Sarà sufficiente aggiungere la seguente voce di configurazione all’interno del blocco properties:

<sonar.exclusions>exclusion1,exclusion2,...</sonar.exclusions>

Dove exclusion1 e exclusion2 sono cartelle o file da escludere, separati da una virgola e senza spazi.

La semantica di esclusione di file e cartelle è la seguente:

  • **/<nome-cartella>/**/*: esclude una cartella e tutte le sue sottocartelle e sottofile. I due asterischi iniziali indicano che la cartella sarà esclusa qualunque sia il suo path all’interno del progetto, così da non dover scrivere il percorso completo.
  • **/<nome-file>.<estensione>: esclude un file, qualunque sia il suo percorso all’interno del progetto.

Esempio di configurazione della sezione properties del pom (fonte: progetto di Ingegneria del Software 2019/2020):

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <sonar.language>java</sonar.language>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <sonar.coverage.exclusions>**/client/**/*,**/constants/**/*, **/server/**/*,**/Santorini.java</sonar.coverage.exclusions>
</properties>

Nel dettaglio, nello snippet sopra indicato vengono esclusi dal coverage report:

  • tutta la cartella client, contenente codice di CLI e GUI;
  • tutta la cartella constants
  • tutta la cartella server, contenente solo le classi di avvio del server (non conteneva nè model nè controller)
  • il file Santorini.java, contenente la main class del progetto.

Struttura delle directory