CI/CD para C#: cómo dejar de desplegar manualmente y empezar a vivir
\n\nSi 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\nCI/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\nPor 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\nCI (Continuous Integration) — es cuando cada uno de tus commits en Git se compila y prueba automáticamente. Nada de «a mí me funciona».
\n\nCD (Continuous Delivery/Deployment) — es cuando después de una compilación exitosa, el código viaja solo al servidor (o a la nube).
\n\nPara 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.
Elegimos la herramienta: GitHub Actions vs GitLab CI vs Jenkins
\n\nPara 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
Si tienes GitLab — el principio es el mismo, la sintaxis es similar. Jenkins lo dejamos para el infierno corporativo.
\n\nEscribimos el primer pipeline para un proyecto C#
\n\nCreamos en la raíz del repositorio el archivo .github/workflows/dotnet.yml. Sí, el archivo debe estar exactamente en esta carpeta.
Aquí tienes un pipeline mínimo funcional que compila el proyecto y ejecuta las pruebas:
\n\nname: .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\nAnalicemos 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
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\nAñadimos code coverage (porque las pruebas sin cobertura son ficción)
\n\nUn pipeline bonito debe mostrar cuánto código está cubierto por las pruebas. Para C# usamos coverlet junto con ReportGenerator.
\n\nPrimero, añade los paquetes NuGet al proyecto de prueba:
\n\ndotnet add YourTestProject.csproj package coverlet.collector\ndotnet add YourTestProject.csproj package coverlet.msbuild\n\nAhora 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