CI/CD para C#: configuración de pipeline desde cero para perezosos y ocupados

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

CI/CD para C#: cómo dejar de desplegar manualmente y empezar a vivir

\n\n

Si todavía compilas tu proyecto C# localmente, subes los builds por FTP y rezas para que nada falle — tengo noticias para ti. En 2025, hacer eso es vergonzoso. Incluso para un pequeño proyecto personal.

\n\n

CI/CD no es magia de seniors que ganan 300k, sino simplemente un conjunto de scripts que hacen la rutina por ti. Hoy configuraremos un pipeline CI/CD completo para C# desde cero. Sin rodeos, con ejemplos reales y análisis de errores.

\n\n

Por cierto, si programas en Python — en nuestro pythonlib.ru también tenemos guías de automatización. Pero hoy trabajamos con C#.

\n\n

¿Qué es CI/CD y por qué lo necesita un desarrollador C#?

\n\n

CI (Continuous Integration) — es cuando cada uno de tus commits en Git se compila y prueba automáticamente. Nada de «a mí me funciona».

\n\n

CD (Continuous Delivery/Deployment) — es cuando después de una compilación exitosa, el código viaja solo al servidor (o a la nube).

\n\n

Para C# esto es especialmente relevante: la compilación con dotnet build puede diferir en diferentes máquinas, y las pruebas todo el mundo se olvida de ejecutarlas. CI/CD resuelve ambos problemas.

\n\n

Elegimos la herramienta: GitHub Actions vs GitLab CI vs Jenkins

\n\n

Para empezar, recomiendo GitHub Actions. ¿Por qué?

\n\n
    \n
  • Gratuito para repositorios públicos (sí, también para C#)
  • \n
  • No necesitas instalar un servidor
  • \n
  • Actions listos para .NET
  • \n
  • YAML — se lee fácilmente
  • \n
\n\n

Si tienes GitLab — el principio es el mismo, la sintaxis es similar. Jenkins lo dejamos para el infierno corporativo.

\n\n

Escribimos el primer pipeline para un proyecto C#

\n\n

Creamos en la raíz del repositorio el archivo .github/workflows/dotnet.yml. Sí, el archivo debe estar exactamente en esta carpeta.

\n\n

Aquí tienes un pipeline mínimo funcional que compila el proyecto y ejecuta las pruebas:

\n\n
name: .NET CI\n\non:\n  push:\n    branches: [ main, develop ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build-and-test:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: '8.0.x'\n\n    - name: Restore dependencies\n      run: dotnet restore\n\n    - name: Build\n      run: dotnet build --no-restore --configuration Release\n\n    - name: Run tests\n      run: dotnet test --no-build --configuration Release --verbosity normal
\n\n

Analicemos paso a paso:

\n\n
    \n
  • on: push — el pipeline se ejecuta al hacer push a main o develop
  • \n
  • runs-on: ubuntu-latest — compilamos en Linux (C# con .NET Core/8+ funciona en todas partes)
  • \n
  • setup-dotnet — instala la versión necesaria del SDK de .NET
  • \n
  • dotnet restore — restaura los paquetes NuGet
  • \n
  • dotnet build — compila la versión de lanzamiento
  • \n
  • dotnet test — ejecuta todas las pruebas del proyecto
  • \n
\n\n

Después del push, ve a la pestaña Actions de tu repositorio — verás cómo se ejecuta el pipeline. Si las pruebas fallan, obtendrás un estado rojo y un correo electrónico.

\n\n

Añadimos code coverage (porque las pruebas sin cobertura son ficción)

\n\n

Un pipeline bonito debe mostrar cuánto código está cubierto por las pruebas. Para C# usamos coverlet junto con ReportGenerator.

\n\n

Primero, añade los paquetes NuGet al proyecto de prueba:

\n\n
dotnet add YourTestProject.csproj package coverlet.collector\ndotnet add YourTestProject.csproj package coverlet.msbuild
\n\n

Ahora actualizamos el paso de pruebas en el pipeline:

\n\n
    - name: Run tests with coverage\n      run: |\n        dotnet test --no-build --configuration Release \\\n          /p:CollectCoverage=true \\\n          /p:CoverletOutputFormat=opencover \\\n          /p:CoverletOutput=./TestResults/coverage.xml\n\n    - name: Install ReportGenerator\n      run: dotnet t                

Blogs

Book Recommendations