# Stratégies de diffusion modernes avec des actions GitHub

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

**Le principe de base : faire relâcher rapidement et sans douleur, et vous relâcherez plus souvent.** C'est essentiel pour le développement agile - des déploiements rapides et fiables créent la boucle de rétroaction rapide dont vous avez besoin. Lorsque le déploiement est effrayant ou lent, les équipes raffolent des changements, augmentant le risque.

Ce guide couvre les stratégies de diffusion que j'utilise en production, des déploiements simples basés sur des tags à l'édition monorepo multi-package. [Actions GitHub](https://docs.github.com/en/actions) les flux de travail dans ce dépôt.

[TOC]

## Aperçu des stratégies de libération

Avant de plonger dans les détails, voici comment les stratégies communes se comparent:

Stratégie du mieux pour la complexité de l'information commune
|----------|----------|------------|-----------|
| **Étiquette** Applications, sorties explicites, startups Low, devs solo, équipes matures
| **Branche** Déploiement continu
| **GitFlow** Releases réglementées, versions multiples
| **Drapeaux basés sur le réseau + Caractéristiques** Grande technologie, startups matures
| **Monorepo multi-emballages** Librairies, bases de code partagées

### Ce qui fonctionne où

**Les startups et les petites équipes**: Commencez par un déploiement basé sur les tags ou des branches. Gardez-le simple - vous pouvez toujours ajouter de la complexité plus tard. Le développement basé sur le réseau avec des drapeaux de fonctionnalités est populaire à l'échelle mais surkill pour les petites équipes.

**Entreprise**: Il faut souvent GitFlow ou similaire pour la conformité, les pistes d'audit et la gestion des rejets. Environnements multiples (dev, QA, mise en scène, prod) avec portes d'approbation.

**Développeurs Solo**: Tag-based est idéal. Poussez une étiquette, le déploiement se produit. Pas de cérémonie, pas de frais généraux.

**Équipes de plate-forme/bibliothèque**: Besoin de stratégies monorepo avec version indépendante par paquet. La version sémantique est critique pour les consommateurs en aval.

## Déploiement par étiquette

La stratégie la plus simple et la plus fiable. Différente balise préfixe la route vers différents environnements ou déclenche différentes actions.

### Ciblage de l'environnement

```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
```

**Pourquoi ça marche ?**: Modèle mental simple, déploiements explicites, retour facile via des balises horodatées.

```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
```

### Version multi-paquets

Pour les monorepos avec plusieurs paquets publiables, utilisez les préfixes d'étiquettes pour identifier le paquet à publier:

```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
```

Extraire la version et l'utiliser tout au long :

```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 }}
```

Pour la version automatique, [MinVer](https://github.com/adamralph/minver) calcule les versions à partir des tags Git:

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

## Déploiement par branche

Déployer automatiquement lorsque le code atterrit sur des branches spécifiques. Commun dans les startups et les équipes en mouvement rapide.

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

**Points positifs**: Pas d'étape manuelle, se déploie lors de la fusion
**Inconvénients**: Déploiement accidentel possible, historique moins explicite

J'utilise une approche hybride - construire sur la poussée de branche (vérification CI), mais ne publier que sur les tags:

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

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

## Mise à jour automatique avec La Tour de Garde

Pour les déploiements auto-organisés, [La Tour de Garde](https://containrrr.dev/watchtower/) tire automatiquement de nouvelles images :

```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
```

**Débit de déploiement**: Push tag → GitHub Actions builds → Push to registry → La Tour de Garde tire → Redémarrage des conteneurs. Temps total: ~5 minutes.

## Portails de qualité

Les déploiements rapides sont inutiles si vous déployez des bogues. Chaque workflow doit inclure des portes :

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

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

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

Pour les paquets multi-cadres, construire toutes les cibles:

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

## Édition sans mot de passe avec OIDC

Approche moderne - pas de secrets à tourner, pas de clés à fuite:

```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 échange son jeton OIDC pour une clé d'API NuGet à courte durée de vie. Configurez la confiance sur NuGet.org pour l'activer.

## Sécurité de la chaîne d'approvisionnement

[Attestations d'artéfacts](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) prouver que vos artefacts ont été construits dans CI, non falsifiés. De plus en plus requis par les entreprises.

```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
```

Les consommateurs vérifient avec: `gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser`

Cela permet d'atteindre les objectifs suivants : [SLSA de niveau 2](https://slsa.dev/spec/v1.0/levels). Pour le niveau 3, utiliser [flux de travail réutilisables](https://docs.github.com/en/actions/sharing-automations/reusing-workflows).

## Aperçu des environnements

Les équipes ont besoin d'intervenants pour prévoir les changements avant la fusion.

**Approche de l'entreprise** - Environnements de prévisualisation basés sur les branches :

```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.
```

**Approche startup/solo** - Tunnel votre machine locale:

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

Ou utiliser [Garde-fils](https://www.wireguard.com/) VPN pour l'accès interne de l'équipe à votre dev machine.

## Conseils pratiques

**Nettoyage des étiquettes**: Des étiquettes git restent dans le coin pour toujours.

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

**Conventions relatives à la désignation**: Soyez cohérent.

- `release-YYYY.MM.DD` pour la production
- `local-feature-name` pour dev
- `packagev1.2.3` pour les bibliothèques

**Secrets**: A conserver dans [Les secrets de GitHub](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), jamais en code. Secrets requis typiquement:

- `DOCKER_HUB_ACCESS_TOKEN`
- `NUGET_API_KEY` (ou utiliser OIDC)
- `NPM_TOKEN`

**Développement de Monorepo**: Utiliser les références de projet pendant le développement, passer aux références de paquet pour la vérification du déploiement :

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

## Déménagement vers Kubernetes

Mêmes principes, différents outils :

Constitué de Docker
|----------------|------------|
La Tour de Garde [ArgoCD](https://argo-cd.readthedocs.io/) / [Flux](https://fluxcd.io/docs/) |
Environnements docker-compose.yml
Redémarrage du conteneur
Rétrospective manuelle Rétrospective GitOps Rétrospective

## Résumé

1. **Démarrer simplement**: Le déploiement par tag couvre la plupart des besoins
2. **Ajouter de la complexité au besoin**: Branche, multi-environnement, attestations
3. **Automatiser les portes de qualité**: Les essais doivent être réussis avant publication
4. **Activer le retour en arrière**: Les tags Timestamped ou l'historique GitOps
5. **Sécurisez votre pipeline**: OIDC pour les secrets, attestations de provenance
6. **Correspondez à votre contexte**: Création d'entreprise Solo dev

Les workflows affichés ici s'exécutent dans ce dépôt - vérifier `.github/workflows/` pour des implémentations complètes.

**Rappelez-vous**: Des déploiements rapides et fiables sont à la base d'un développement agile. Investissez tôt dans votre pipeline de libération.