Skip to content
Open
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
41 changes: 1 addition & 40 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -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
38 changes: 38 additions & 0 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
@@ -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
159 changes: 75 additions & 84 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,132 +1,123 @@
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:
name: Test
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"
4 changes: 2 additions & 2 deletions tests/FinancialUtils.Tests/CalculatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down