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
19 changes: 2 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
name: CI

# Pruebas JUnit 5 + cobertura JaCoCo (QA-06 / SCRUM-1123) con umbral bloqueante
# (jacoco:check en `mvn verify`, ver pom.xml) y análisis SonarCloud con espera del
# Quality Gate (US-03.1.1-M6.3 / SCRUM-1227). El paso de Sonar corre solo si el
# secret SONAR_TOKEN existe: así un PR no falla mientras DevOps crea el proyecto
# Trama-AS_MANI-Java en SonarCloud.
# (jacoco:check en `mvn verify`, ver pom.xml). El análisis de SonarQube y su
# Quality Gate corren en quality-gate.yml (QA4-02 / SCRUM-1265).

on:
push:
Expand All @@ -18,14 +16,9 @@ jobs:
test:
name: Pruebas (Java 17)
runs-on: ubuntu-latest
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
# Sonar necesita el historial para atribuir código nuevo en PRs.
fetch-depth: 0

- name: Set up JDK 17
uses: actions/setup-java@v4
Expand All @@ -46,11 +39,3 @@ jobs:
target/site/jacoco/
target/surefire-reports/
if-no-files-found: warn

- name: SonarCloud + Quality Gate
if: env.SONAR_TOKEN != ''
run: mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121:sonar -Dsonar.qualitygate.wait=true

- name: Aviso si Sonar no está configurado
if: env.SONAR_TOKEN == ''
run: echo "::warning::SONAR_TOKEN no configurado; se omitió el análisis de SonarCloud y su Quality Gate."
129 changes: 129 additions & 0 deletions .github/workflows/quality-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Quality Gate

# QA4-02 (SCRUM-1265): análisis de SonarQube Community con Quality Gate
# bloqueante (ADR-0005, Políticas §14.1).
#
# El servidor SonarQube vive en la VM de Calidad (red privada 10.43.x.x), que los
# runners de GitHub no alcanzan. Por eso el trabajo se divide en dos jobs:
# 1. pruebas_cobertura: corre en ubuntu-latest. Aquí se ejecuta el código del
# repositorio (mvn verify con jacoco:check) y se generan el bytecode, las
# dependencias y el reporte jacoco.xml.
# 2. sonar_quality_gate: corre en el runner self-hosted de la VM de Calidad
# (label "calidad"). Solo descarga el artefacto y ejecuta el scanner; no
# ejecuta Maven ni código del repositorio en la VM.
#
# SonarQube Community no analiza ramas ni PRs, así que se usan dos proyectos:
# - mani-java: push a develop (estado oficial de la rama).
# - mani-java-pr: pull requests, para no pisar el estado de develop.
#
# Para que el gate BLOQUEE el merge, el ruleset de develop, release y main debe
# exigir los dos checks: "Pruebas y cobertura" y "Sonar Quality Gate". Si las
# pruebas fallan, el job de Sonar queda omitido y GitHub cuenta un job omitido
# como aprobado.
#
# Requisitos: secreto SONAR_TOKEN y variable SONAR_HOST_URL (URL del servidor en
# la VM de Calidad), definidos en el repositorio o en la organización.

on:
pull_request:
branches: [develop, release, main]
push:
branches: [develop]

permissions:
contents: read

# En PR se cancela la corrida anterior; en push a develop cada commit conserva
# su análisis.
concurrency:
group: quality-gate-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
pruebas_cobertura:
name: Pruebas y cobertura
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configurar JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Pruebas con cobertura y umbral (JaCoCo)
run: mvn -B verify

# El scanner necesita las dependencias para resolver tipos (sonar.java.libraries).
- name: Copiar dependencias de compilación
run: mvn -B dependency:copy-dependencies -DincludeScope=compile -DoutputDirectory=target/dependency

# jacoco.xml referencia las clases por paquete y archivo, sin rutas
# absolutas, así que sirve tal cual en el workspace del runner self-hosted.
- name: Publicar compilado y cobertura
uses: actions/upload-artifact@v4
with:
name: compilado_java
path: |
target/classes
target/test-classes
target/dependency
target/site/jacoco/jacoco.xml
if-no-files-found: error
retention-days: 3

sonar_quality_gate:
name: Sonar Quality Gate
needs: pruebas_cobertura
# Los PRs desde forks no llegan al runner de la VM: su código no es de
# confianza y no tienen acceso a los secretos. En vez de omitir el job (un
# job omitido cuenta como aprobado), el job corre en ubuntu-latest y falla.
runs-on: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && 'ubuntu-latest' || fromJSON('["self-hosted","calidad"]') }}
steps:
- name: Bloquear PRs desde forks
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: |
echo "::error::Los PRs desde forks no pasan el Quality Gate. Abra el PR desde una rama de Trama-AS."
exit 1

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Descargar compilado y cobertura
uses: actions/download-artifact@v4
with:
name: compilado_java
path: target

# Si falta el secreto o la variable, el job falla. Un check omitido o en
# verde sin análisis daría una falsa señal de calidad.
- name: Verificar configuración de SonarQube
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
run: |
if [ -z "$SONAR_TOKEN" ]; then
echo "::error::SONAR_TOKEN no está configurado en los secretos del repositorio."
exit 1
fi
if [ -z "$SONAR_HOST_URL" ]; then
echo "::error::SONAR_HOST_URL no está configurada en las variables del repositorio."
exit 1
fi

# v8.2.2 fijada por SHA del tag (ba9859e).
- name: Análisis de SonarQube y espera del Quality Gate
uses: sonarsource/sonarqube-scan-action@ba9859eae8dd6bd29e412f25ddbbef3d032000f4
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=${{ github.event_name == 'pull_request' && 'mani-java-pr' || 'mani-java' }}
-Dsonar.qualitygate.wait=true
-Dsonar.qualitygate.timeout=300
9 changes: 2 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@

<properties>
<java.version>17</java.version>
<!-- SonarCloud (ADR-0005). El scanner Maven lee estas propiedades; el token
(SONAR_TOKEN) es un secret del repositorio. -->
<sonar.organization>trama-as</sonar.organization>
<sonar.projectKey>Trama-AS_MANI-Java</sonar.projectKey>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<sonar.coverage.exclusions>**/ManiRulesApplication.java</sonar.coverage.exclusions>
<!-- SonarQube (ADR-0005): la configuración del análisis vive en
sonar-project.properties y la ejecuta .github/workflows/quality-gate.yml. -->
<!-- Umbral local de cobertura: `mvn verify` falla por debajo (jacoco:check). -->
<jacoco.minimum.line>0.85</jacoco.minimum.line>
<jacoco.minimum.branch>0.80</jacoco.minimum.branch>
Expand Down
27 changes: 27 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# =====================================================================
# Configuración de SonarQube para MANI-Java (Rules Service)
# Referencia: ADR-0005 (SAST en CI/CD con SonarQube), QA4-02 (SCRUM-1265)
# Servidor: SonarQube Community de la VM de Calidad (self-hosted, no SonarCloud)
# =====================================================================

# Identificación del proyecto. En pull requests el workflow quality-gate.yml
# sobrescribe la clave con mani-java-pr (Community no analiza ramas ni PRs).
sonar.projectKey=mani-java
sonar.projectName=MANI-Java

sonar.sourceEncoding=UTF-8
sonar.java.source=17

# Rutas de código fuente y pruebas
sonar.sources=src/main/java
sonar.tests=src/test/java

# Bytecode y dependencias compilados por el job "Pruebas y cobertura" en
# ubuntu-latest y descargados como artefacto: el runner de la VM no ejecuta Maven.
sonar.java.binaries=target/classes
sonar.java.test.binaries=target/test-classes
sonar.java.libraries=target/dependency/*.jar

# Reporte de cobertura generado por "mvn verify" (jacoco-maven-plugin)
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
sonar.coverage.exclusions=**/ManiRulesApplication.java
Loading