diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b90d68d..b445c1c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,40 +1 @@ -# CODEOWNERS -# -# Define quién debe revisar cambios en partes específicas del repositorio. -# GitHub solicita automáticamente la revisión de los owners cuando un PR -# modifica archivos que coinciden con algún patrón. -# -# Sintaxis: patrón @usuario-o-equipo -# -# Las reglas se evalúan de arriba hacia abajo. -# La última regla que coincida con un archivo gana. -# Los patrones siguen la misma sintaxis que .gitignore. - -# --- Owner global --- -# Aplica a todo lo que no tenga una regla más específica abajo. -* @TU_USUARIO - -# --- Librería principal --- -# Cualquier cambio en el código fuente requiere revisión de los maintainers. -/src/ @TU_USUARIO - -# --- Tests --- -# Los tests pueden revisarlos los mismos developers, no solo maintainers. -# En un equipo real aquí irían @equipo/developers o usuarios individuales. -/tests/ @TU_USUARIO - -# --- Workflows de CI/CD --- -# Los cambios en pipelines tienen un impacto alto: pueden exponer secrets, -# modificar qué checks son requeridos, o cambiar tiempos de build. -# Requieren revisión explícita de quien administra la infraestructura. -/.github/workflows/ @TU_USUARIO - -# --- Configuración de seguridad y políticas --- -# CODEOWNERS mismo, editorconfig y configuración del repo. -/.github/CODEOWNERS @TU_USUARIO -/.editorconfig @TU_USUARIO - -# --- Documentación --- -# El README puede actualizarlo cualquier contributor. -# Si quisieras restricción, agregarías un owner específico aquí. -*.md @TU_USUARIO +* @jhnnalx \ No newline at end of file diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml new file mode 100644 index 0000000..09e8c66 --- /dev/null +++ b/.github/workflows/Test.yml @@ -0,0 +1,38 @@ +name: Test + +on: + push: + branches: + - main + - 'feature/**' + - 'fix/**' + pull_request: + branches: + - main + +env: + DOTNET_VERSION: '9.0.x' + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + format: + name: Format check + runs-on: ubuntu-latest + outputs: + dotnet-version: ${{ steps.setup-dotnet.outputs.dotnet-version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + id: setup-dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restore dependencias + run: dotnet restore + + - name: Verificar formato de código + run: dotnet format --verify-no-changes --verbosity diagnostic \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e37477..02d4fde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,67 +1,65 @@ -name: CI +# Estado esperado de .github/workflows/01-ci.yml al terminar el laboratorio 04. +# Cambios respecto al 03: el trabajo se parte en dos jobs unidos con `needs`, +# y los binarios viajan de un job a otro como artefacto. +# +# Ojo con el costo: dos jobs significan dos runners, dos checkouts y dos +# restores. Partir jobs se justifica cuando ganas paralelismo o cuando +# necesitas condiciones distintas, no por estética. + +name: 01 - CI on: push: branches: - main - - 'feature/**' - - 'fix/**' + - 'lab/**' pull_request: branches: - main + workflow_dispatch: + +permissions: + contents: read env: DOTNET_VERSION: '9.0.x' - DOTNET_NOLOGO: true - DOTNET_CLI_TELEMETRY_OPTOUT: true - -jobs: - format: - name: Format check - runs-on: ubuntu-latest - outputs: - dotnet-version: ${{ steps.setup-dotnet.outputs.dotnet-version }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup .NET - id: setup-dotnet - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: Restore dependencias - run: dotnet restore + DOTNET_NOLOGO: 'true' + DOTNET_CLI_TELEMETRY_OPTOUT: 'true' - - name: Verificar formato de código - run: dotnet format --verify-no-changes --verbosity diagnostic +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true +jobs: build: name: Build runs-on: ubuntu-latest - needs: format + outputs: + version-sdk: ${{ steps.sdk.outputs.dotnet-version }} steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Descargar el código al runner + uses: actions/checkout@v7 - - name: Setup .NET ${{ needs.format.outputs.dotnet-version }} - uses: actions/setup-dotnet@v4 + - name: Instalar el SDK de .NET + id: sdk + uses: actions/setup-dotnet@v6 with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Restore dependencias + - name: Restaurar dependencias run: dotnet restore - - name: Compilar (Release) + - name: Compilar en Release run: dotnet build --configuration Release --no-restore - - name: Publicar artefacto compilado - uses: actions/upload-artifact@v4 + - name: Publicar los binarios compilados + uses: actions/upload-artifact@v7 with: - name: build-output - path: src/FinancialUtils/bin/Release/ - retention-days: 7 + name: binarios + path: | + src/**/bin/Release/ + tests/**/bin/Release/ + retention-days: 1 if-no-files-found: error test: @@ -69,64 +67,57 @@ jobs: runs-on: ubuntu-latest needs: build steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Descargar el código al runner + uses: actions/checkout@v7 - - name: Setup .NET - uses: actions/setup-dotnet@v4 + - name: Instalar el SDK de .NET + uses: actions/setup-dotnet@v6 with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Restore dependencias + - name: Bajar los binarios del job anterior + uses: actions/download-artifact@v7 + with: + name: binarios + + # El artefacto trae bin/, pero no obj/. `dotnet test --no-build` necesita + # el archivo obj/project.assets.json para resolver rutas de salida, así que + # hay que restaurar de nuevo. Es rápido porque no vuelve a compilar. + - name: Restaurar dependencias run: dotnet restore - - name: Ejecutar pruebas con cobertura + - name: Ejecutar pruebas run: | dotnet test \ --configuration Release \ - --no-restore \ - --collect:"XPlat Code Coverage" \ - --results-directory ./coverage \ - --logger "trx;LogFileName=test-results.trx" + --no-build \ + --logger "trx;LogFileName=resultados.trx" \ + --results-directory ./resultados - - name: Subir reporte de cobertura - uses: actions/upload-artifact@v4 + - name: Publicar resultados de pruebas + if: always() + uses: actions/upload-artifact@v7 with: - name: coverage-report - path: coverage/ - retention-days: 7 + name: resultados-de-pruebas + path: ./resultados + retention-days: 5 if-no-files-found: error - - name: Subir resultados de pruebas - uses: actions/upload-artifact@v4 + - name: Escribir el resumen del run if: always() - with: - name: test-results - path: coverage/**/*.trx - retention-days: 7 - if-no-files-found: ignore - - summary: - name: Summary - runs-on: ubuntu-latest - needs: [format, build, test] - if: always() - steps: - - name: Descargar resultados de pruebas - uses: actions/download-artifact@v4 - with: - name: test-results - path: test-results - continue-on-error: true - - - name: Generar resumen del pipeline run: | - echo "## Resultado del pipeline" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Job | Estado |" >> $GITHUB_STEP_SUMMARY - echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Format | ${{ needs.format.result }} |" >> $GITHUB_STEP_SUMMARY - echo "| Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY - echo "| Test | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo ".NET version: \`${{ needs.format.outputs.dotnet-version }}\`" >> $GITHUB_STEP_SUMMARY + TRX=$(find ./resultados -name '*.trx' | head -1) + TOTAL=$(grep -o 'total="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + PASADAS=$(grep -o 'passed="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + FALLIDAS=$(grep -o 'failed="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + { + echo "### Resultado de las pruebas" + echo "" + echo "| Métrica | Valor |" + echo "|---------|-------|" + echo "| Total | ${TOTAL:-0} |" + echo "| Pasadas | ${PASADAS:-0} |" + echo "| Fallidas | ${FALLIDAS:-0} |" + echo "" + echo "SDK usado en build: \`${{ needs.build.outputs.version-sdk }}\`" + } >> "$GITHUB_STEP_SUMMARY" diff --git a/tests/FinancialUtils.Tests/CalculatorTests.cs b/tests/FinancialUtils.Tests/CalculatorTests.cs index 6bab0b2..97dfa17 100644 --- a/tests/FinancialUtils.Tests/CalculatorTests.cs +++ b/tests/FinancialUtils.Tests/CalculatorTests.cs @@ -148,10 +148,10 @@ public void LoanPayment_InvalidMonths_ThrowsArgumentException(int months) public void NetPresentValue_CalculatesCorrectly() { // Inversión inicial -1000, flujos futuros de 400 por 3 periodos a tasa 10% - // NPV = -1000 + 400/1.1 + 400/1.21 + 400/1.331 ≈ -0.64 + // NPV = -1000 + 400/1.1 + 400/1.21 + 400/1.331 ≈ -5.26 var cashFlows = new[] { -1000m, 400m, 400m, 400m }; var result = Calculator.NetPresentValue(0.10m, cashFlows); - Assert.Equal(-0.64m, result); + Assert.Equal(-5.26m, result); } [Fact]