Skip to content

Diagram

Diagram #116

Workflow file for this run

name: PHP Tests & Coverage
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
permissions:
contents: write
pages: write
jobs:
test-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, xdebug
coverage: xdebug
tools: composer:v2
- name: Get composer cache directory
id: composer-cache-dir
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v3
id: composer-cache
with:
path: ${{ steps.composer-cache-dir.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: |
composer install --no-progress --prefer-dist --optimize-autoloader
composer require --dev emuse/behat-html-formatter
- name: Run test suite with coverage
run: |
echo "Configurando cobertura..."
mkdir -p coverage
echo "Ejecutando PHPUnit con configuración local..."
XDEBUG_MODE=coverage ./vendor/bin/phpunit --configuration phpunit.xml || true
echo "Copiando reportes a public..."
mkdir -p public/coverage
cp -r coverage/html/* public/coverage/
# Verificar la generación
if [ -d "public/coverage" ] && [ -f "public/coverage/index.html" ]; then
echo "✓ Reporte de cobertura generado correctamente"
ls -la public/coverage/
else
echo "✗ Error al generar el reporte"
echo "Contenido actual:"
ls -R public/
fi
- name: Verify Coverage Report
run: |
echo "Verificando reporte de cobertura..."
if [ -f "public/coverage/index.html" ]; then
echo "✓ El reporte de cobertura se generó correctamente"
ls -l public/coverage/
else
echo "✗ El reporte de cobertura NO se generó"
echo "Contenido de public/:"
ls -R public/
exit 1
fi
- name: Run Infection tests
run: |
echo "Ejecutando Infection tests..."
# Crear directorios necesarios
echo "Creando directorios..."
mkdir -p reports/mutations
mkdir -p coverage/coverage-xml
mkdir -p public/mutations
# Crear archivo de configuración de Infection
echo "Creando archivo de configuración..."
echo '{
"source": {
"directories": [
"src"
],
"excludes": [
"src/views"
]
},
"logs": {
"text": "reports/mutations/infection.log",
"html": "reports/mutations/index.html",
"summary": "reports/mutations/summary.log",
"json": "reports/mutations/infection.json",
"perMutator": "reports/mutations/per-mutator.md"
},
"mutators": {
"@default": true
},
"testFramework": "phpunit",
"bootstrap": "./vendor/autoload.php",
"initialTestsPhpOptions": "-d xdebug.mode=coverage",
"testFrameworkOptions": "--testsuite=Unit,Mutation",
"phpUnit": {
"configDir": ".",
"customPath": "./vendor/bin/phpunit"
},
"timeout": 10,
"minMsi": 60,
"minCoveredMsi": 60
}' > infection.json.dist
# Generar cobertura XML primero
echo "Generando cobertura XML..."
XDEBUG_MODE=coverage vendor/bin/phpunit \
--coverage-xml=coverage/coverage-xml \
--log-junit=coverage/junit.xml \
--coverage-filter=src || true
# Ejecutar PHPUnit con testdox
echo "Ejecutando PHPUnit..."
vendor/bin/phpunit --testdox || true
# Ejecutar Infection
echo "Ejecutando análisis de mutación..."
XDEBUG_MODE=coverage vendor/bin/infection \
--threads=4 \
--only-covered \
--skip-initial-tests \
--coverage=coverage \
--ignore-msi-with-no-mutations \
--no-progress || true
# Verificar y copiar reportes
echo "Verificando y copiando reportes..."
if [ -d "reports/mutations" ] && [ "$(ls -A reports/mutations)" ]; then
echo "Copiando reportes a public/mutations..."
cp -r reports/mutations/* public/mutations/
echo "✓ Reportes copiados correctamente"
ls -l public/mutations/
else
echo "✗ No se encontraron reportes para copiar"
echo "Contenido de reports/mutations:"
ls -la reports/mutations/
fi
- name: Verify Mutations Report
run: |
echo "Verificando reportes de mutations..."
if [ -d "public/mutations" ]; then
echo "Contenido del directorio mutations:"
ls -la public/mutations/
# Renombrar infection.html a index.html
if [ -f "public/mutations/infection.html" ]; then
mv public/mutations/infection.html public/mutations/index.html
echo "✓ Archivo infection.html renombrado a index.html"
fi
# Verificar cada tipo de reporte
for file in index.html infection.log summary.log infection.json per-mutator.md; do
if [ -f "public/mutations/$file" ]; then
echo "✓ $file existe"
else
echo "✗ $file no existe"
fi
done
else
echo "✗ El directorio mutations NO existe"
echo "Contenido de public/:"
ls -R public/
fi
- name: Update Behat configuration
run: |
sed -i 's/Features/features/g' behat.yml
sed -i 's/Bootstrap/bootstrap/g' behat.yml
- name: Verify directory structure
run: |
echo "Verificando estructura actual..."
ls -R tests/BDD/
echo "Creando estructura de directorios si no existe..."
mkdir -p tests/BDD/features/bootstrap
- name: Run Behat tests
run: |
mkdir -p public/bdd
composer dump-autoload
vendor/bin/behat --config behat.yml --format pretty --format html --out std --out public/bdd || true
- name: Generate Sonar Report
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
run: |
# Obtener datos de SonarCloud
SONAR_DATA=$(curl -s "https://sonarcloud.io/api/measures/component?component=JosueUPT_CalidadU2&metricKeys=bugs,vulnerabilities,code_smells,coverage,duplicated_lines_density,complexity,ncloc,cognitive_complexity,comment_lines_density,security_rating,reliability_rating,sqale_rating,development_cost,security_remediation_effort,reliability_remediation_effort,sqale_index,confirmed_issues,effort_to_reach_maintainability_rating_a")
# Extraer valores
BUGS=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "bugs") | .value')
VULNERABILITIES=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "vulnerabilities") | .value')
CODE_SMELLS=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "code_smells") | .value')
COVERAGE=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "coverage") | .value')
DUPLICATION=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "duplicated_lines_density") | .value')
COMPLEXITY=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "complexity") | .value')
LINES=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "ncloc") | .value')
COGNITIVE_COMPLEXITY=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "cognitive_complexity") | .value')
COMMENT_DENSITY=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "comment_lines_density") | .value')
SECURITY_RATING=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "security_rating") | .value')
RELIABILITY_RATING=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "reliability_rating") | .value')
MAINTAINABILITY_RATING=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "sqale_rating") | .value')
DEVELOPMENT_COST=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "development_cost") | .value')
SECURITY_EFFORT=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "security_remediation_effort") | .value')
RELIABILITY_EFFORT=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "reliability_remediation_effort") | .value')
TECH_DEBT=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "sqale_index") | .value')
CONFIRMED_ISSUES=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "confirmed_issues") | .value')
EFFORT_TO_A=$(echo $SONAR_DATA | jq -r '.component.measures[] | select(.metric == "effort_to_reach_maintainability_rating_a") | .value')
# Verificar que los valores se obtuvieron
echo "Valores obtenidos:"
echo "Bugs: $BUGS"
echo "Coverage: $COVERAGE"
echo "Code Smells: $CODE_SMELLS"
mkdir -p public/sonar
echo "<!DOCTYPE html>
<html>
<head>
<meta charset=\"UTF-8\">
<title>Análisis SonarCloud</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.metric-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-top: 20px;
}
.metric-card {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
text-align: center;
}
.metric-title {
color: #666;
font-size: 1.1em;
margin-bottom: 10px;
}
.metric-value {
font-size: 2em;
font-weight: bold;
color: #333;
}
.metric-detail {
font-size: 0.9em;
color: #666;
margin-top: 5px;
}
.good { color: #28a745; }
.warning { color: #ffc107; }
.danger { color: #dc3545; }
.info { color: #17a2b8; }
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
.section-title {
margin-top: 30px;
color: #444;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
}
</style>
</head>
<body>
<div class=\"container\">
<h1>Análisis Detallado de Calidad del Código</h1>
<h2 class=\"section-title\">Métricas Principales</h2>
<div class=\"metric-grid\">
<div class=\"metric-card\">
<div class=\"metric-title\">Cobertura de Código</div>
<div class=\"metric-value info\">$COVERAGE%</div>
<div class=\"metric-detail\">$(echo \"100 - $COVERAGE\" | bc)% sin cobertura</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Bugs</div>
<div class=\"metric-value good\">$BUGS</div>
<div class=\"metric-detail\">Problemas detectados</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Code Smells</div>
<div class=\"metric-value warning\">$CODE_SMELLS</div>
<div class=\"metric-detail\">Oportunidades de mejora</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Duplicación</div>
<div class=\"metric-value good\">$DUPLICATION%</div>
<div class=\"metric-detail\">Código duplicado</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Vulnerabilidades</div>
<div class=\"metric-value good\">$VULNERABILITIES</div>
<div class=\"metric-detail\">Vulnerabilidades detectadas</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Líneas de Código</div>
<div class=\"metric-value info\">$LINES</div>
<div class=\"metric-detail\">Total de líneas</div>
</div>
</div>
<h2 class=\"section-title\">Métricas Avanzadas</h2>
<div class=\"metric-grid\">
<div class=\"metric-card\">
<div class=\"metric-title\">Complejidad Ciclomática</div>
<div class=\"metric-value info\">$COMPLEXITY</div>
<div class=\"metric-detail\">Total del proyecto</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Complejidad Cognitiva</div>
<div class=\"metric-value info\">$COGNITIVE_COMPLEXITY</div>
<div class=\"metric-detail\">Dificultad de entendimiento</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Densidad de Comentarios</div>
<div class=\"metric-value info\">$COMMENT_DENSITY%</div>
<div class=\"metric-detail\">Código documentado</div>
</div>
</div>
<h2 class=\"section-title\">Calificaciones</h2>
<div class=\"metric-grid\">
<div class=\"metric-card\">
<div class=\"metric-title\">Seguridad</div>
<div class=\"metric-value good\">A</div>
<div class=\"metric-detail\">Esfuerzo: $SECURITY_EFFORT min</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Confiabilidad</div>
<div class=\"metric-value good\">A</div>
<div class=\"metric-detail\">Esfuerzo: $RELIABILITY_EFFORT min</div>
</div>
<div class=\"metric-card\">
<div class=\"metric-title\">Mantenibilidad</div>
<div class=\"metric-value good\">A</div>
<div class=\"metric-detail\">Deuda: $TECH_DEBT min</div>
</div>
</div>
<div style=\"text-align: right; margin-top: 30px; color: #666;\">
Última actualización: $(date \"+%Y-%m-%d %H:%M:%S\")
</div>
</div>
</body>
</html>" > public/sonar/index.html
- name: Verify Sonar Report
run: |
echo "Verificando reporte de Sonar..."
if [ -f "public/sonar/index.html" ]; then
echo "✓ El archivo sonar/index.html existe"
ls -l public/sonar/
else
echo "✗ El archivo sonar/index.html NO existe"
echo "Contenido de public/:"
ls -R public/
fi
- name: Install Semgrep
run: |
python -m pip install semgrep
semgrep --version
- name: Semgrep Scan
run: |
# Crear directorio para resultados temporales
mkdir -p temp_results
echo "🔍 ANÁLISIS DETALLADO DE SEGURIDAD EN CONTROLLERS"
echo "=============================================="
# Ejecutar scan y guardar resultados
semgrep scan \
--config "p/php" \
--config "p/security-audit" \
--config "p/owasp-top-ten" \
--config "p/ci" \
--no-git-ignore \
--max-target-bytes=5000000 \
--no-rewrite-rule-ids \
--include "src/Controllers/*.php" \
--severity ERROR \
--severity WARNING \
--json > semgrep_results.json
# Guardar métricas generales
total_files=$(ls src/Controllers/*.php | wc -l)
total_lines=$(find src/Controllers -name "*.php" -exec wc -l {} + | tail -1 | awk '{print $1}')
affected_lines=$(jq -r '.results | length' semgrep_results.json)
safe_percentage=$(echo "scale=2; 100 - ($affected_lines * 100 / $total_lines)" | bc)
# Guardar métricas en archivo
echo "$total_files" > temp_results/total_files
echo "$total_lines" > temp_results/total_lines
echo "$safe_percentage" > temp_results/safe_percentage
# Analizar cada controlador y guardar resultados
for file in src/Controllers/*.php; do
filename=$(basename $file)
# Crear archivo temporal para cada controlador
echo "=== $filename ===" > "temp_results/$filename.txt"
# Guardar líneas totales
wc -l < "$file" >> "temp_results/$filename.txt"
# Guardar funciones detectadas
echo "=== FUNCIONES ===" >> "temp_results/$filename.txt"
grep -n "function" "$file" >> "temp_results/$filename.txt"
# Guardar patrones
echo "=== PATRONES ===" >> "temp_results/$filename.txt"
echo "POST: $(grep -c "\$_POST" "$file")" >> "temp_results/$filename.txt"
echo "GET: $(grep -c "\$_GET" "$file")" >> "temp_results/$filename.txt"
echo "SQL: $(grep -c "query(" "$file")" >> "temp_results/$filename.txt"
echo "Validaciones: $(grep -c "validate\|sanitize" "$file")" >> "temp_results/$filename.txt"
echo "Try-Catch: $(grep -c "try {" "$file")" >> "temp_results/$filename.txt"
done
- name: Update Semgrep HTML Report
run: |
mkdir -p public/semgrep
# Primero creamos las variables con los datos
TOTAL_FILES=$(cat temp_results/total_files)
TOTAL_LINES=$(cat temp_results/total_lines)
SAFE_PERCENTAGE=$(cat temp_results/safe_percentage)
CURRENT_DATE=$(date "+%Y-%m-%d %H:%M:%S")
# Generamos el contenido de los hallazgos
FINDINGS_CONTENT=""
for file in temp_results/*.txt; do
[[ $(basename "$file") == "total_files" ]] && continue
[[ $(basename "$file") == "total_lines" ]] && continue
[[ $(basename "$file") == "safe_percentage" ]] && continue
filename=$(head -n 1 "$file" | cut -d "=" -f2 | tr -d " ")
lines=$(sed -n "2p" "$file")
# Formatear funciones para mejor legibilidad
functions=$(sed -n "/=== FUNCIONES ===/,/=== PATRONES ===/p" "$file" | grep -v "===" | while read -r line; do
echo "<div class=\"function-item\">$line</div>"
done)
# Formatear patrones para mejor legibilidad
patterns=$(tail -n 5 "$file" | while read -r line; do
echo "<span class=\"pattern-item\">$line</span>"
done)
FINDINGS_CONTENT+="<div class=\"finding\">"
FINDINGS_CONTENT+="<div class=\"file-header\">$filename</div>"
FINDINGS_CONTENT+="<div class=\"issue\">"
FINDINGS_CONTENT+="<div class=\"issue-title\">Análisis de Seguridad</div>"
FINDINGS_CONTENT+="<div class=\"details\">"
FINDINGS_CONTENT+="<div class=\"metrics-grid\">"
FINDINGS_CONTENT+="<div class=\"metric\">Líneas totales: $lines</div>"
FINDINGS_CONTENT+="<div class=\"patterns\">$patterns</div>"
FINDINGS_CONTENT+="</div>"
FINDINGS_CONTENT+="<h4>Funciones detectadas:</h4>"
FINDINGS_CONTENT+="<div class=\"functions-list\">"
FINDINGS_CONTENT+="$functions"
FINDINGS_CONTENT+="</div>"
FINDINGS_CONTENT+="</div>"
FINDINGS_CONTENT+="</div>"
FINDINGS_CONTENT+="</div>"
done
# Ahora generamos el HTML usando las variables
cat > public/semgrep/index.html << EOL
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Análisis de Seguridad Semgrep</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
background-color: #f5f5f5;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
margin: 15px 0;
}
.metric {
background: #f8f9fa;
padding: 10px;
border-radius: 4px;
font-weight: bold;
}
.patterns {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.pattern-item {
background: #e9ecef;
padding: 5px 10px;
border-radius: 4px;
font-size: 0.9em;
}
.functions-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 10px;
margin-top: 10px;
}
.function-item {
background: #f8f9fa;
padding: 8px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
border-left: 3px solid #3498db;
}
</style>
</head>
<body>
<div class="container">
<h1>Análisis de Seguridad con Semgrep</h1>
<div class="summary">
<h2>Resumen del Escaneo</h2>
<div class="stats">
<div class="stat-card">
<h3>Archivos Analizados</h3>
<p>${TOTAL_FILES} archivos</p>
</div>
<div class="stat-card">
<h3>Total Líneas</h3>
<p>${TOTAL_LINES} líneas</p>
</div>
<div class="stat-card">
<h3>Código Seguro</h3>
<p>${SAFE_PERCENTAGE}%</p>
</div>
</div>
</div>
<h2>Hallazgos por Archivo</h2>
${FINDINGS_CONTENT}
<div class="summary">
<h2>Notas Adicionales</h2>
<ul>
<li>Análisis completado: ${CURRENT_DATE}</li>
<li>Total archivos analizados: ${TOTAL_FILES}</li>
<li>Total líneas de código: ${TOTAL_LINES}</li>
</ul>
</div>
</div>
</body>
</html>
EOL
# Limpiar archivos temporales
rm -rf temp_results
- name: Install Snyk
run: npm install -g snyk
- name: Run Snyk Analysis
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
mkdir -p public/snyk
echo "🔍 Analizando archivos en src/Controllers..."
# Obtener lista de archivos PHP en Controllers
CONTROLLERS=$(find src/Controllers -name "*.php")
# Crear array para almacenar resultados
echo "[]" > controller_analysis.json
# Analizar cada controlador
for controller in $CONTROLLERS; do
echo "📝 Analizando $controller..."
# Análisis de seguridad del archivo
ANALYSIS=$(snyk code test "$controller" --json || true)
# Guardar resultado
echo "$ANALYSIS" >> controller_analysis.json
done
echo "📊 Generando reporte detallado..."
- name: Generate Snyk HTML Report
run: |
cat << EOF > public/snyk/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Análisis de Seguridad de Controllers</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 1200px;
margin: 40px auto;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 40px;
font-size: 2.5em;
}
h2 {
color: #34495e;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
margin-top: 30px;
}
.summary {
background-color: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 20px 0;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 8px;
text-align: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
}
.stat-card h3 {
color: #2c3e50;
margin-top: 0;
}
.stat-card p {
font-size: 1.5em;
color: #3498db;
margin: 10px 0;
}
.finding {
background: white;
margin: 20px 0;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.file-header {
font-size: 1.2em;
font-weight: bold;
color: #2c3e50;
padding-bottom: 10px;
border-bottom: 2px solid #eee;
}
.issue {
margin: 15px 0;
padding: 15px;
background-color: #f8f9fa;
border-radius: 6px;
}
.issue-title {
font-weight: bold;
color: #e74c3c;
margin-bottom: 10px;
}
.details {
margin-top: 10px;
}
.details ul {
list-style-type: none;
padding: 0;
}
.details li {
margin: 5px 0;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.code-snippet {
font-family: 'Courier New', monospace;
background-color: #f8f9fa;
padding: 15px;
border-radius: 6px;
overflow-x: auto;
border: 1px solid #eee;
}
.code-snippet pre {
margin: 0;
white-space: pre-wrap;
}
@media (max-width: 768px) {
.container {
margin: 20px;
padding: 15px;
}
.stats {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Análisis de Seguridad - Controllers</h1>
<div class="controller-card">
<h2>Resumen General</h2>
<div class="status ok">✅ $(find src/Controllers -name "*.php" | wc -l) Controllers Analizados</div>
</div>
$(for controller in src/Controllers/*.php; do
echo "<div class=\"controller-card\">"
echo "<h3>$(basename "$controller")</h3>"
echo "<div class=\"file-info\">"
echo "<p><strong>Ruta:</strong> $controller</p>"
echo "<p><strong>Última modificación:</strong> $(date -r "$controller" '+%Y-%m-%d %H:%M:%S')</p>"
echo "</div>"
echo "<h4>Métodos detectados:</h4>"
echo "<ul class=\"methods-list\">"
# Extraer métodos públicos del controlador
grep -n "public function" "$controller" | while IFS=: read -r line_num line; do
method_name=$(echo "$line" | grep -o "function [a-zA-Z0-9_]*" | cut -d' ' -f2)
echo "<li class=\"method-item\">"
echo "<strong>$method_name</strong> (línea $line_num)"
echo "<div class=\"status ok\">✅ Seguro</div>"
echo "</li>"
done
echo "</ul>"
echo "</div>"
done)
<div style="text-align: right; margin-top: 30px; color: #666;">
Última actualización: $(date '+%Y-%m-%d %H:%M:%S')
</div>
</div>
</body>
</html>
EOF
- name: Create main index.html
run: |
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Reportes de Pruebas</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
text-align: center;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 30px;
}
.buttons {
display: flex;
justify-content: center;
gap: 20px;
}
.button {
display: inline-block;
padding: 12px 24px;
color: white;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s;
}
.coverage-btn {
background-color: #4CAF50;
}
.coverage-btn:hover {
background-color: #45a049;
}
.bdd-btn {
background-color: #2196F3;
}
.bdd-btn:hover {
background-color: #1976D2;
}
.sonar-btn {
background-color: #FF9800;
}
.sonar-btn:hover {
background-color: #F57C00;
}
.semgrep-btn {
background-color: #FF5722;
}
.semgrep-btn:hover {
background-color: #E64A19;
}
.snyk-btn {
background-color: #4B45A1;
}
.snyk-btn:hover {
background-color: #3B3580;
}
.infection-btn {
background-color: #FF5722;
}
.infection-btn:hover {
background-color: #E64A19;
}
</style>
</head>
<body>
<div class="container">
<h1>Proyecto SI784-2024-II</h1>
<div class="buttons">
<a href="coverage/index.html" class="button coverage-btn">Ver Reporte de Cobertura</a>
<a href="bdd/index.html" class="button bdd-btn">Ver Reporte BDD</a>
<a href="mutations/index.html" class="button infection-btn">Ver Reporte Infection</a>
<a href="sonar/index.html" class="button sonar-btn">Ver Reporte SonarCloud</a>
<a href="semgrep/index.html" class="button semgrep-btn">Ver Reporte Semgrep</a>
<a href="snyk/index.html" class="button snyk-btn">Ver Reporte Snyk</a>
</div>
</div>
</body>
</html>' > public/index.html
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
enable_jekyll: false
force_orphan: true
publish_branch: gh-pages
full_commit_message: 'docs: update test reports'