# Estrategias modernas de lanzamiento con acciones de GitHub

<!--category-- DevOps, CI/CD, GitHub Actions -->
<datetime class="hidden">2025-12-04T12:00</datetime>

**El principio básico: hacer liberaciones rápidas e indoloras, y se liberarán más a menudo.** Esto es fundamental para el desarrollo ágil: los despliegues rápidos y fiables crean el bucle de retroalimentación rápido que necesita. Cuando el despliegue es aterrador o lento, los equipos cambian por lotes, aumentando el riesgo. Cuando el despliegue es aburrido y automático, envía cambios pequeños con frecuencia.

Esta guía cubre las estrategias de lanzamiento que utilizo en la producción, desde implementaciones simples basadas en etiquetas hasta publicaciones monorepo multi-paquete. [Acciones de GitHub](https://docs.github.com/en/actions) flujos de trabajo en este repositorio.

[TOC]

## Liberar estrategias a la vista

Antes de sumergirse en detalles, aquí está cómo se comparan las estrategias comunes:

Estrategia Mejor para la Complejidad Común
|----------|----------|------------|-----------|
| **Basado en etiquetas** Aplicaciones, lanzamientos explícitos Low Startups, devs en solitario, equipos maduros
| **Sucursales** Despliegue continuo Bajo Startups, equipos de movimiento rápido
| **GitFlow** Releases reguladas, múltiples versiones  High  Enterprise, cumplimiento-pesado
| **Banderas basadas en troncos + características** Equipos de alta velocidad  Medio  Gran tecnología, startups maduras
| **Monorepo multi-paquete** Bibliotecas, bases de código compartidas Equipos de plataformas, proyectos OSS

### ¿Qué funciona donde?

**Startups & Small Teams**: Comience con la implementación basada en etiquetas o sucursales. Manténgalo simple - siempre puede agregar complejidad más tarde. Desarrollo basado en troncos con banderas de características es popular a escala, pero en exceso para equipos pequeños.

**Empresa**: A menudo requiere GitFlow o similar para el cumplimiento, seguimientos de auditoría y gestión de liberaciones. Múltiples entornos (dev, QA, estadificación, prod) con puertas de aprobación.

**Desarrolladores en solitario**: A base de etiquetas es ideal. Empujar una etiqueta, el despliegue ocurre. No hay ceremonia, no hay gastos generales.

**Equipos de plataforma/biblioteca**: Necesita estrategias monorepo con versión independiente por paquete. La versión semántica es fundamental para los consumidores intermedios.

## Despliegue basado en etiquetas

La estrategia más simple y confiable. Diferentes prefijos de etiquetas se dirigen a diferentes entornos o desencadenan diferentes acciones.

### Objetivos para el medio ambiente

```yaml
on:
  push:
    tags:
      - 'release-*'  # Production
      - 'local-*'    # Dev environment
```

```yaml
- name: Build Docker image
  run: |
    TAG_NAME=${GITHUB_REF#refs/tags/}
    if [[ "$TAG_NAME" == local-* ]]; then
      docker build -t myapp:local .
    else
      docker build -t myapp:latest -t myapp:$(date +%s) .
    fi
```

**¿Por qué funciona?**: Modelo mental simple, implementaciones explícitas, fácil retroceso a través de etiquetas de tiempo.

```bash
# Deploy to production
git tag release-v2024.12.01 && git push origin release-v2024.12.01

# Deploy to dev
git tag local-feature-test && git push origin local-feature-test
```

### Versión multi-paquete

Para monorepos con varios paquetes publicables, utilice prefijos de etiquetas para identificar qué paquete lanzar:

```yaml
# Different workflows, different tag patterns
# umami-net.yml
on:
  push:
    tags: ['umamiv*.*.*']  # e.g., umamiv1.0.5

# fetchextension.yml
on:
  push:
    tags: ['fetchextension-v*.*.*']  # e.g., fetchextension-v1.2.0
```

Extraer la versión y utilizarla en todo:

```yaml
- name: Extract version
  run: echo "VERSION=${GITHUB_REF#refs/tags/umamiv}" >> $GITHUB_OUTPUT

- name: Build & Pack
  run: |
    dotnet build -c Release -p:Version=${{ steps.version.outputs.VERSION }}
    dotnet pack -c Release -p:PackageVersion=${{ steps.version.outputs.VERSION }}
```

Para la versión automática, [MinVer](https://github.com/adamralph/minver) calcula las versiones de las etiquetas Git:

```xml
<PackageReference Include="MinVer" Version="6.0.0" PrivateAssets="all" />
<PropertyGroup>
  <MinVerTagPrefix>umamiv</MinVerTagPrefix>
</PropertyGroup>
```

## Despliegue basado en subdivisiones

Desplegarse automáticamente cuando el código aterriza en ramas específicas. Común en startups y equipos de rápido movimiento.

```yaml
on:
  push:
    branches: [main]      # → Production
    # branches: [develop] # → Staging
```

**Pros**: No hay paso manual, se despliega en la fusión
**Contras**: Despliegues accidentales posibles, historia menos explícita

Utilizo un enfoque híbrido - construir sobre el empuje de la rama (comprobación de CI), pero sólo publicar en etiquetas:

```yaml
on:
  push:
    tags: ['scheduler-*']
    branches: [main, local]

jobs:
  build:
    # Always build
  publish:
    if: startsWith(github.ref, 'refs/tags/')  # Only publish on tags
```

## Actualizaciones automáticas con Watchtower

Para los despliegues auto-anfitriones, [Watchtower](https://containrrr.dev/watchtower/) automáticamente tira de nuevas imágenes:

```yaml
services:
  app:
    image: myapp:latest
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 300  # Check every 5 minutes
```

**Flujo de despliegue**: Push tag → GitHub Acciones se construye → Push to register → Watchtower tira → Contenedor se reinicia. Tiempo total: ~5 minutos.

## Puertas de calidad

Las implementaciones rápidas son inútiles si implementas errores. Cada flujo de trabajo debe incluir puertas:

```yaml
- name: Run tests
  run: dotnet test --configuration Release

- name: Build
  run: dotnet build --configuration Release

# Tests or build fail → workflow stops → no publish
```

Para paquetes multiframework, construya todos los objetivos:

```yaml
- run: dotnet build -c Release --framework net8.0
- run: dotnet build -c Release --framework net9.0
```

## Publicación sin contraseña con la OIDC

Enfoque moderno - sin secretos para rotar, sin claves para filtrar:

```yaml
permissions:
  id-token: write
  contents: read

- uses: NuGet/login@v1
  with:
    user: 'myusername'

- run: dotnet nuget push *.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }}
```

GitHub intercambia su token OIDC por una clave de API NuGet de corta duración. Configure confianza en NuGet.org para habilitarlo.

## Seguridad de la cadena de suministro

[Atestaciones de artefactos](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) prueban que sus artefactos fueron construidos en CI, no manipulados, cada vez más requeridos por las empresas.

```yaml
permissions:
  id-token: write
  attestations: write

- uses: docker/build-push-action@v6
  id: push
  with:
    push: true
    tags: myapp:latest

- uses: actions/attest-build-provenance@v2
  with:
    subject-name: index.docker.io/myuser/myapp
    subject-digest: ${{ steps.push.outputs.digest }}
    push-to-registry: true
```

Los consumidores verifican con: `gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser`

Esto logra [SLSA Nivel 2](https://slsa.dev/spec/v1.0/levels). Para el nivel 3, use [Flujos de trabajo reutilizables](https://docs.github.com/en/actions/sharing-automations/reusing-workflows).

## Previsualizar entornos

Los equipos necesitan que las partes interesadas previsualicen los cambios antes de fusionarse.

**Enfoque empresarial** - Entornos de vista previa basados en ramas:

```yaml
on:
  pull_request:
    types: [opened, synchronize]

- run: |
    BRANCH=$(echo ${{ github.head_ref }} | sed 's/[^a-zA-Z0-9]/-/g')
    docker build -t myapp:preview-$BRANCH .
    # Deploy to k8s namespace, cloud platform, etc.
```

**Método de puesta en marcha/solo** - Túnel de su máquina local:

```bash
# Cloudflare Tunnel (free)
cloudflared tunnel run --url http://localhost:5000 my-preview
# → https://my-preview.cfargotunnel.com
```

O usar [Alambre](https://www.wireguard.com/) VPN para el acceso interno del equipo a su máquina de desarrollo.

## Consejos prácticos

**Limpieza de etiquetas**: Las etiquetas Git se quedan para siempre.

```bash
git tag -d old-test-tag                      # Delete local
git push origin :refs/tags/old-test-tag      # Delete remote
```

**Convenios sobre la designación de nombres**: Sea consistente.

- `release-YYYY.MM.DD` para la producción
- `local-feature-name` para dev
- `packagev1.2.3` para las bibliotecas

**Secretos**: Almacenar en [Secretos de GitHub](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), nunca en código. Secretos requeridos típicamente:

- `DOCKER_HUB_ACCESS_TOKEN`
- `NUGET_API_KEY` (o utilizar OIDC)
- `NPM_TOKEN`

**Desarrollo de Monorepo**: Utilice las referencias del proyecto durante el desarrollo, cambie a las referencias del paquete para la verificación del despliegue:

```xml
<ProjectReference Include="..\MyLib\MyLib.csproj" />
<!-- <PackageReference Include="MyLib" Version="1.0.0" /> -->
```

## Mudarse a Kubernetes

Los mismos principios, diferentes herramientas:

Docker Compositor  Kubernetes
|----------------|------------|
# La Atalaya # [ArgoCD](https://argo-cd.readthedocs.io/) / [Flux](https://fluxcd.io/docs/) |
docker-compose.yml ambientes  Namespaces
Reanudación de contenedores Despliegue de rollos
GitOps rollback

## Resumen

1. **Inicio simple**: El despliegue basado en etiquetas cubre la mayoría de las necesidades
2. **Añadir complejidad cuando sea necesario**: Sucursales, multimedios, certificaciones
3. **Automatizar puertas de calidad**: Las pruebas deben pasar antes de publicar
4. **Habilitar la reversión**: Historial de etiquetas o GitOps con Timestamped
5. **Asegure su tubería**: OIDC para secretos, certificaciones de procedencia
6. **Coincide con su contexto**: Solo dev • startup • empresa

Los flujos de trabajo mostrados aquí se ejecutan en este repositorio - check `.github/workflows/` para las implementaciones completas.

**Recuerda.**: Las implementaciones rápidas y confiables son la base del desarrollo ágil.