# Strategie di rilascio moderne con azioni GitHub

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

**Il principio di base: rendere i rilasci veloci e indolore, e si rilascerà più spesso.** Questo è fondamentale per lo sviluppo agile - le distribuzioni rapide e affidabili creano il loop di feedback veloce di cui hai bisogno. Quando la distribuzione è spaventosa o lenta, i team batch up cambiano, aumentando il rischio. Quando la distribuzione è noiosa e automatica, spedisci spesso piccoli cambiamenti.

Questa guida copre le strategie di rilascio che uso in produzione, dalle semplici implementazioni basate su tag alla pubblicazione multi-package monorepo. Tutti gli esempi provengono dal reale [Azioni GitHub](https://docs.github.com/en/actions) flussi di lavoro in questo repository.

[TOC]

## Strategie di rilascio a una lancia

Prima di tuffarsi nei dettagli, ecco come le strategie comuni confrontano:

| Strategy | Best For | Complexity | Common In |
|----------|----------|------------|-----------|
| **Tag-based** | Applicazioni, uscite esplicite | Basso | Startups, solo devs, team maturi |
| **Basato su un ramo** | Dispiegamento continuo | Basso | Startup, squadre in movimento rapido |
| **GitFlowCity name (optional, probably does not need a translation)** | Release regolamentati, versioni multiple | High | Enterprise, compliance-heavy |
| **Opzioni basate su Trunk + Funzionalità** | Squadre ad alta velocità | Media | Big tech, startup mature |
| **Pacchetto multi-monorepo** | Biblioteche, basi di codice condivise | Medium | Platform teams, OSS projects |

### Cosa funziona dove

**Startup e squadre piccole**: Inizia con l'implementazione basata su tag o rami. Mantieni la semplicità - puoi sempre aggiungere la complessità in seguito. Lo sviluppo basato su Trunk con flag di funzionalità è popolare in scala, ma l'overkill per i piccoli team.

**Impresa**: Spesso richiede GitFlow o simili per la conformità, audit trail, e la gestione del rilascio. Ambienti multipli (dev, QA, messa in scena, prod) con cancelli di omologazione.

**Sviluppatori singoli**: Tag-based è l'ideale. Spingere un tag, la distribuzione avviene. Nessuna cerimonia, nessuna sopra spese.

**Piattaforma/Squadre di biblioteca**: Necessita di strategie monorepo con versione indipendente per pacchetto. La versione semantica è fondamentale per i consumatori a valle.

## Tag-based deployment

La strategia più semplice e affidabile. Different tag prefixes route to different environments or trigger different actions.

### Obiettivo per l'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
```

**Perché funziona**: Modello mentale semplice, spiegamenti espliciti, facile rollback tramite tag con timestamped.

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

### Versione multi-package

Per le monorepos con più pacchetti pubblicabili, utilizzare i prefissi dei tag per identificare quale pacchetto rilasciare:

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

Estrarre la versione e usarla in tutto:

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

Per la versione automatica, [MinVerCity name (optional, probably does not need a translation)](https://github.com/adamralph/minver) calcola le versioni dai tag Git:

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

## Distribuzione a livello settoriale

Distribuire automaticamente quando il codice atterra su rami specifici. Comune in startup e team in rapido movimento.

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

**Pro**: Nessun passo manuale, implementa sulla fusione
**Contro**: Implementazioni accidentali possibili, cronologia meno esplicita

Uso un approccio ibrido - basato su branch push (verifica CI), ma pubblica solo sui tag:

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

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

## Aggiornamenti automatici con Watchtower

Per i dispiegamenti auto-ospitati, [Torre di guardia](https://containrrr.dev/watchtower/) automaticamente tira nuove immagini:

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

**Flusso di distribuzione**: Push tag → GitHub Azioni costruisce → Push to Registry → Torre di controllo tira → Riavvia contenitore. Tempo totale: ~5 minuti.

## Cancelli di qualità

Le implementazioni veloci sono inutili se implementa i bug. Ogni flusso di lavoro dovrebbe includere i cancelli:

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

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

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

Per i pacchetti multi-frame, creare tutti gli obiettivi:

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

## Pubblicazione senza password con OIDC

Approccio moderno - nessun segreto da ruotare, nessuna chiave da perdere:

```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 scambia il suo token OIDC per una chiave NuGet API di breve durata. Configura la fiducia su NuGet.org per abilitarla.

## Sicurezza della catena di approvvigionamento

[Certificazioni di artefatti](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) Dimostra che i tuoi artefatti sono stati costruiti in CI, non manomessi.

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

I consumatori verificano con: `gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser`

A tal fine [SLSA Livello 2](https://slsa.dev/spec/v1.0/levels). Per il livello 3, utilizzare [flussi di lavoro riutilizzabili](https://docs.github.com/en/actions/sharing-automations/reusing-workflows).

## Anteprima degli ambienti

Le squadre hanno bisogno di stakeholder per visualizzare in anteprima i cambiamenti prima di fondersi.

**Approccio alle imprese** - Ambienti di anteprima basati su branch:

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

**Approccio di avvio/solo** - Tunnel la vostra macchina locale:

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

O usare [WireguardCity name (optional, probably does not need a translation)](https://www.wireguard.com/) VPN per l'accesso interno del team alla macchina dev.

## Consigli pratici

**Pulizia etichetta**: Git tag rimangono in giro per sempre.

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

**Convenzioni di denominazione**: Siate coerenti.

- `release-YYYY.MM.DD` per la produzione
- `local-feature-name` per dev
- `packagev1.2.3` per le biblioteche

**Segreti**: Conservare in [Segreti di GitHub](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), mai in codice. Segreti richiesti in genere:

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

**Sviluppo di Monorepo**: Utilizzare i riferimenti del progetto durante lo sviluppo, passare ai riferimenti dei pacchetti per la verifica dell'implementazione:

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

## Spostamento su Kubernetes

Stessi principi, diversi strumenti:

| Docker Compose | Kubernetes |
|----------------|------------|
| Torre di Controllo | [ArgoCD](https://argo-cd.readthedocs.io/) / [Flux](https://fluxcd.io/docs/) |
|Ambienti docker-compose.yml |Namespace |
| Riavvio del contenitore | spiegamento del rotolamento |
| Rollback manuale | GitOps rollback |

## Sommario

1. **Avvia semplice**: Tag-based deployment copre la maggior parte delle esigenze
2. **Aggiungi complessità quando necessario**: Branch-based, multi-environment, attestati
3. **Automatizzare i cancelli di qualità**: I test devono passare prima di pubblicare
4. **Abilita il rollback**: Timestamped tags or GitOps history
5. **Fissa la tua pipeline**: OIDC per segreti, attestati di provenienza
6. **Corrisponde al contesto**: Startup di Solo dev

I flussi di lavoro mostrati qui vengono eseguiti in questo repository - check `.github/workflows/` per implementazioni complete.

**Ricorda**: Gli implementazioni rapide e affidabili sono alla base dello sviluppo agile. Investite presto nella vostra pipeline di rilascio.