Introducción: Cuando "funciona en mi máquina" es un desastre
Cada desarrollador de C++ ha escuchado al menos una vez la frase: "A mí me funciona todo, es extraño que a ti te falle". O la ha dicho él mismo. Compilación de plantillas, enlazado, peculiaridades de diferentes estándares (C++17, C++20), macros dependientes de la plataforma: C++ está lleno de sorpresas que surgen al cambiar de entorno.
Un pipeline CI/CD (Integración Continua / Despliegue Continuo) para C++ no es un lujo, sino una necesidad. Compila el proyecto automáticamente, ejecuta pruebas, verifica la calidad del código y, si tiene éxito, despliega la aplicación en un servidor (o publica la biblioteca). En este artículo configuraremos un pipeline completo desde cero, utilizando GitHub Actions, CMake y C++. Obtendrá una configuración lista para usar que puede adaptar a su proyecto.
1. Preparación del proyecto: estructura y sistema de compilación
Antes de escribir el pipeline, debemos poner el proyecto en orden. Usaremos CMake, el estándar de facto para proyectos C++ modernos. Nuestro ejemplo será una utilidad simple para procesar cadenas con pruebas unitarias en Google Test.
Estructura del repositorio
my_cpp_project/├── .github/│ └── workflows/│ └── ci.yml # Archivo del pipeline├── src/│ ├── main.cpp│ └── string_utils.cpp├── include/│ └── string_utils.hpp├── tests/│ ├── CMakeLists.txt│ └── test_string_utils.cpp├── CMakeLists.txt # CMake raíz├── Dockerfile # Para el despliegue final└── README.mdCMakeLists.txt raíz
Compilamos la biblioteca y el ejecutable. Observe la exportación de pruebas:
cmake_minimum_required(VERSION 3.20)project(MyStringUtils VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Biblioteca principaladd_library(string_utils STATIC src/string_utils.cpp include/string_utils.hpp)target_include_directories(string_utils PUBLIC include)
# Archivo ejecutableadd_executable(my_app src/main.cpp)target_link_libraries(my_app PRIVATE string_utils)
# Pruebas (opcional, se activan con una opción)option(BUILD_TESTS "Build unit tests" ON)if(BUILD_TESTS) enable_testing() add_subdirectory(tests)endif()Ejemplo de prueba (tests/test_string_utils.cpp)
#include <gtest/gtest.h>#include "string_utils.hpp"
TEST(StringUtilsTest, ToUpper) { EXPECT_EQ(to_upper("hello"), "HELLO"); EXPECT_EQ(to_upper("C++20"), "C++20");}
TEST(StringUtilsTest, Trim) { EXPECT_EQ(trim(" spaced "), "spaced"); EXPECT_EQ(trim("\\t\\r"), "");}Ahora que el proyecto está listo, pasamos a lo principal: la configuración del pipeline CI/CD para C++.
2. GitHub Actions: escribiendo el primer pipeline
GitHub Actions es la herramienta CI/CD más popular en el código abierto. Su configuración se escribe en YAML y se encuentra en la carpeta .github/workflows. Crearemos el archivo ci.yml.
Estructura básica: ejecución al hacer push y en PR
name: C++ CI/CD Pipeline
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: build-and-test: runs-on: ubuntu-latest
steps: - name: Checkout code uses: actions/checkout@v4
- name: Install dependencies run: | sudo apt-get update sudo apt-get install -y cmake g++ libgtest-dev
- name: Configure CMake run: cmake -B build -DCMAKE_BUILD_TYPE=Release
- name: Build run: cmake --build build --parallel $(nproc)
- name: Run tests run: cd build && ctest --output-on-failureEste es un pipeline CI/CD para C++ mínimo pero funcional. Si las pruebas fallan, el pipeline termina con un error y usted recibe una notificación. Pero iremos más allá.