# Moderna utgivningsstrategier med GitHub-åtgärder

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

**Kärnan princip: göra utsläpp snabbt och smärtfritt, och du kommer att släppa oftare.** Detta är avgörande för en smidig utveckling - snabba, tillförlitliga distributioner skapar den snabba återkopplingsslinga du behöver. När utplaceringen är skrämmande eller långsam, grupper batch upp förändringar, ökande risk. När utplacering är tråkigt och automatiskt, du skeppar små förändringar ofta.

Denna guide täcker de utgivningsstrategier jag använder i produktionen, från enkla tag-baserade distributioner till multi-paket monorepo publicering. Alla exempel kommer från verkliga [GitHub-åtgärder](https://docs.github.com/en/actions) arbetsflöden i det här arkivet.

[TOC]

## Utgivningsstrategier vid en blick

Före dykning i detaljer, här är hur gemensamma strategier jämföra:

"Strategi  på bästa sätt för komplexitet"
|----------|----------|------------|-----------|
| **Taggbaserad** Applikationer, explicita utgåvor  med låga startups, solo devs, mogna team  och
| **Filialbaserad** till Kontinuerlig driftsättning  och låg startups, snabbrörliga team
| **GitFlow Ordförande** på Regulerade utgåvor, flera versioner  på hög nivå  på företag, compliance-tungt
| **Trunk-baserade + funktionsflaggor** Höghastighetsteam med medelhög teknik, mogna startups
| **Multipelförpackning för Monorepo** på biblioteken, delade kodbaser  på medelhöga plattformar, OSS-projekt

### Vad som fungerar där

**Startups och små team**: Börja med taggbaserad eller grenbaserad distribution. Håll det enkelt - du kan alltid lägga till komplexitet senare. Trunk-baserad utveckling med funktionsflaggor är populärt i skala men överdöd för små lag.

**Företag**: Ofta kräver GitFlow eller liknande för efterlevnad, verifieringsspår, och release management. Flera miljöer (dev, QA, iscensättning, prod) med godkännande grindar. Artifact intyg allt mer krävs för leveranskedjan säkerhet.

**Solo utvecklare**: Tag-baserad är perfekt. Tryck på en tagg, utplacering händer. Ingen ceremoni, ingen overhead.

**Plattform/Biblioteksgrupper**: Behöver monorepo strategier med oberoende versionering per paket. Semantisk versionering är avgörande för nedströms konsumenter.

## Taggbaserad distribution

Den enklaste och mest tillförlitliga strategin. Olika taggar prefixar rutt till olika miljöer eller utlösa olika åtgärder.

### Miljöriktande åtgärder

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

**Varför det fungerar**: Enkel mental modell, explicita utplaceringar, enkel rollback via tidsstämplade taggar.

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

### Flerpackningsversioner

För monorepos med flera publiceringsbara paket, använd taggprefix för att identifiera vilket paket som ska släppas:

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

Extrahera versionen och använd den i hela:

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

För automatisk versionshantering, [MinVer](https://github.com/adamralph/minver) beräknar versioner från Git-taggar:

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

## Filialbaserad utbyggnad

Utplacera automatiskt när koden landar på specifika grenar. Vanliga i startups och snabbrörliga team.

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

**Förmåner**: Inga manuella steg, driftsättningar vid sammanfogning
**Nackdelar**: Oavsiktlig driftsättning möjlig, mindre explicit historia

Jag använder en hybrid metod - bygga på gren push (CI-verifiering), men bara publicera på taggar:

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

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

## Automatisk uppdatering av Vakttornet

För självvärdiga utplaceringar, [Vakttornet](https://containrrr.dev/watchtower/) drar automatiskt nya bilder:

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

**Utbyggnadsflöde**: Push tag → GitHub Åtgärder bygger → Tryck till register → Watchtower drar → Container omstarter. Total tid: ~5 minuter.

## Kvalitetsportar

Snabba distributioner är värdelösa om du distribuerar buggar. Varje arbetsflöde bör innehålla grindar:

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

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

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

För flerramspaket, bygg alla mål:

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

## Lösenordslös publicering med OIDC

Modernt tillvägagångssätt - inga hemligheter att rotera, inga nycklar att läcka:

```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 byter sin OIDC- token mot en kortlivad NuGet API-nyckel. Konfigurera förtroendet på NuGet.org för att aktivera detta.

## Säkerhet i försörjningskedjan

[Artefaktintyg](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) Bevisa att dina artefakter byggdes i CI, inte manipulerade.

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

Konsumenterna kontrollerar med: `gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser`

Detta uppnår [SLSA nivå 2](https://slsa.dev/spec/v1.0/levels). För nivå 3, användning [Återanvändbara arbetsflöden](https://docs.github.com/en/actions/sharing-automations/reusing-workflows).

## Förhandsgranskningsmiljöer

Lag behöver intressenter för att förhandsgranska ändringar innan sammanslagning.

**Företagsstrategi** - Branch-baserade förhandsgranskningsmiljöer:

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

**Uppstart/solo-inflygning** - Tunnel din lokala maskin:

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

Eller använd [Trådvakt](https://www.wireguard.com/) VPN för intern åtkomst till din dev-maskin.

## Praktiska tips

**Taggstädning**: Git taggar stanna kvar för alltid.

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

**Namngivningskonventioner**: Var konsekvent.

- `release-YYYY.MM.DD` för framställning
- `local-feature-name` för dev
- `packagev1.2.3` för bibliotek

**Hemligheter**: Förvaras i [GitHub hemligheter](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), aldrig i kod. Obligatoriska hemligheter typiskt:

- `DOCKER_HUB_ACCESS_TOKEN`
- `NUGET_API_KEY` (eller använd OIDC)
- `NPM_TOKEN`

**Monorepo-utveckling**: Använd projektreferenser under utveckling, byt till paketreferenser för verifiering av installation:

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

## Flytta till Kubernetes

Samma principer, olika verktyg:

på Docker Komposiera  på Kubernetes
|----------------|------------|
på Vakttornet [Förbehåll IIIA-PT-17](https://argo-cd.readthedocs.io/) / [Flux](https://fluxcd.io/docs/) |
på docker-compose.yml-miljöer
på omstart av container  med rullande driftsättning  på plats
på manuell upprullning  på GitOps upprullning  på

## Sammanfattning

1. **Starta enkelt**: Tag-baserad installation täcker de flesta behov
2. **Lägg till komplexitet vid behov**: branschbaserade, multi-environment, intyg
3. **Automatisera kvalitetsgrindar**: Testerna måste vara klara innan de publiceras
4. **Aktivera upprullning**: Tidsstämplade taggar eller GitOps historik
5. **Säkra din rörledning**: OIDC för hemligheter, intyg om härkomst
6. **Matcha ditt sammanhang**: Entreprenörskapsföretaget Solo dev  entreprenörskap

De arbetsflöden som visas här körs i det här arkivet - kontrollera `.github/workflows/` för fullständiga genomföranden.

**Kom ihåg**: Snabba, pålitliga driftsättningar är grunden för smidig utveckling. Investera i din lansering pipeline tidigt.