Saltar al contenido principal
ArceApps Logo ArceApps

Semantic Versioning en CD/CI: La Ciencia Exacta del Despliegue Continuo

⏱️ 4 min de lectura
Semantic Versioning en CD/CI: La Ciencia Exacta del Despliegue Continuo

📐 Teoría: El Contrato Social del Versionado

El Semantic Versioning (SemVer) no es solo una convención de nombrado (X.Y.Z); es un contrato social entre el desarrollador y el consumidor del software (ya sea otro desarrollador o el usuario final).

En el formato MAJOR.MINOR.PATCH:

  • MAJOR: Cambios incompatibles (Breaking Changes). El contrato se rompe.
  • MINOR: Funcionalidad nueva compatible hacia atrás. El contrato se expande.
  • PATCH: Corrección de bugs compatible hacia atrás. El contrato se mantiene.

El Reto en CI/CD (Continuous Delivery)

En un entorno de CD, los humanos no deberían decidir versiones. Si un humano decide “esta es la versión 2.0”, introduce subjetividad y error. La versión debe ser una función determinista del historial de cambios.

Versión(t) = Versión(t-1) + Impacto(Commit_t)

🔄 El Bucle de Retroalimentación de Versiones

Un pipeline de CI/CD moderno para Android debe seguir este bucle estrictamente:

  1. Code Change: Desarrollador hace commit siguiendo Conventional Commits.
  2. Analysis: CI analiza el commit. ¿Es feat? ¿Es fix? ¿Es BREAKING CHANGE?
  3. Calculation: CI calcula la nueva versión basándose en la última etiqueta (tag) y el impacto del cambio.
  4. Release: CI genera el artefacto (APK/AAB) con esa versión.
  5. Tagging: CI etiqueta el commit con la nueva versión, cerrando el ciclo.

🛠️ Implementación Práctica en GitHub Actions

Vamos a construir un pipeline que implemente esta teoría usando la herramienta semantic-release o equivalentes.

Paso 1: Análisis de Commits (The Parser)

Necesitamos una herramienta que entienda Conventional Commits. Usaremos PaulHatch/semantic-version.

      - name: Calculate Semantic Version
        id: semver
        uses: PaulHatch/semantic-version@v5.3.0
        with:
          # Define la raíz del código fuente para ignorar cambios en docs/readme
          change_path: "app/src"
          # Mapeo de tipos de commit a incrementos de versión
          major_pattern: "(MAJOR|BREAKING CHANGE)"
          minor_pattern: "feat:"
          # Formato de salida
          version_format: "${major}.${minor}.${patch}"

Paso 2: Cálculo de VersionCode (Android Specific)

Como vimos en Automatización de Versionado, Android necesita un entero. Aquí aplicamos la teoría de conjuntos: el versionCode debe ser una proyección inyectiva del versionName.

      - name: Compute Android Version Code
        id: compute_code
        run: |
          # Extraer componentes semánticos
          MAJOR=$(echo ${{ steps.semver.outputs.version }} | cut -d. -f1)
          MINOR=$(echo ${{ steps.semver.outputs.version }} | cut -d. -f2)
          PATCH=$(echo ${{ steps.semver.outputs.version }} | cut -d. -f3)

          # Algoritmo de Posicionamiento Decimal
          # Permite: 21 Major, 99 Minor, 99 Patch -> 219999
          CODE=$((MAJOR * 10000 + MINOR * 100 + PATCH))

          echo "android_code=$CODE" >> $GITHUB_OUTPUT

Paso 3: Inmutabilidad del Artefacto

Una regla de oro en DevOps es: Construye una vez, despliega en todas partes. El APK que se prueba en QA debe ser bit a bit idéntico al que va a Producción.

Esto significa que la versión se inyecta en el momento del build, y ese artefacto “viaja” por los entornos. No reconstruimos para producción.

      - name: Build Once
        run: ./gradlew bundleRelease -PversionName=${{ steps.semver.outputs.version }} -PversionCode=${{ steps.compute_code.outputs.android_code }}
        
      - name: Upload Artifact
        uses: actions/upload-artifact@v4
        with:
          name: app-release
          path: app/build/outputs/bundle/release/*.aab

⚠️ Manejo de Pre-Releases (Alpha/Beta)

El versionado semántico también cubre ciclos de vida inestables.

  • 1.0.0-alpha.1: Primera alpha.
  • 1.0.0-beta.1: Feature freeze.
  • 1.0.0-rc.1: Release Candidate.

Estrategia de Ramas

  • feature/* -> Genera versiones alpha (1.1.0-alpha.x).
  • develop -> Genera versiones beta (1.1.0-beta.x).
  • main -> Genera versiones finales (1.1.0).

Configuración del Action para manejar prereleases:

      - name: Determine Prerelease Label
        id: prerelease
        run: |
          if [[ $GITHUB_REF == *"feature/"* ]]; then
            echo "label=alpha" >> $GITHUB_OUTPUT
          elif [[ $GITHUB_REF == *"develop"* ]]; then
            echo "label=beta" >> $GITHUB_OUTPUT
          else
            echo "label=" >> $GITHUB_OUTPUT
          fi

📉 Errores Comunes y Cómo Evitarlos

1. El “Tag Manual”

Desarrollador hace git tag v1.0.0 manualmente. Problema: Rompe la fuente única de verdad. Si el CI intenta generar v1.0.0 después, fallará. Solución: Bloquear la creación de tags manuales en GitHub para todos excepto el bot de CI.

2. Commits “Sucios”

Mensajes como “wip”, “fix bug”, “changes”. Problema: El analizador semántico no sabe qué hacer (default a PATCH o ignora). Solución: Usar un commit-msg hook o un lint action que obligue al formato Conventional Commits.

      - name: Lint Commit Messages
        uses: wagoid/commitlint-github-action@v5

3. Explosión del VersionCode

Si usas timestamps o números de build de GitHub (GITHUB_RUN_NUMBER) directamente. Problema: Si cambias de proveedor de CI (de GitHub a GitLab), el contador se reinicia y Google Play rechaza actualizaciones (Error: Version code 1 < 500). Solución: Usar siempre el cálculo derivado de SemVer (Major*10000...). Es agnóstico a la plataforma de CI.

🎯 Conclusión

Implementar Semantic Versioning en tu CI/CD no es burocracia; es ingeniería de confiabilidad. Transformas el acto subjetivo y peligroso de “versionar” en un proceso matemático, determinista y completamente automatizado.

Cuando un manager pregunte “¿Qué hay en la versión 2.1.0?”, no necesitas buscar en emails. El sistema te dirá exactamente: “Contiene todas las feat desde la 2.0.0 y es compatible hacia atrás”. Eso es poder.

También te puede interesar

Automatización de Versionado con GitHub Actions: La Revolución del Desarrollador Android
Android 10 de diciembre de 2025

Automatización de Versionado con GitHub Actions: La Revolución del Desarrollador Android

Descubre cómo automatizar completamente el versionado de tu app Android con GitHub Actions: desde commits hasta Google Play Store, sin intervención manual.

Leer artículo
GitHub Actions para Google Play Store: La Guía Definitiva de CD en Android
GitHub Actions 30 de octubre de 2025

GitHub Actions para Google Play Store: La Guía Definitiva de CD en Android

Aprende a configurar un pipeline de Continuous Deployment robusto que compile, firme y publique tu App Android automáticamente en Google Play Store.

Leer artículo
GitHub Actions: El Motor de tu CI/CD
GitHub Actions 25 de octubre de 2025

GitHub Actions: El Motor de tu CI/CD

Aprende los fundamentos de GitHub Actions para automatizar tus flujos de trabajo, desde la ejecución de tests hasta el despliegue automático.

Leer artículo