# Moderna utsläppsstrategier med GitHub actions

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

**Kernprincipen: : gör släppen snabba och smärtfria, , och du kommer att släppa mer ofta.** Detta är viktigt för agil utveckling. - snabb , tillförlitliga inplantningar skapar den snabba återkopplingsloop du behöver. ♫ . ♫ När inplanting är skrämmande eller långsamt ♫

Den här handboken omfattar de utsläppsstrategier som jag använder i produktionen, från enkel tag, -, till multi, -, paket-monorepopublicering och .. Alla exempel kommer från verkliga [GitHub-aktioner](https://docs.github.com/en/actions) arbetsflöden i detta arkiv.

[TOC]

## Release strategier på en titt

Innan man dyker in i detaljer

| Strategin | | | bäst för || | komplexitet | | 3 | vanliga i |
|----------|----------|------------|-----------|
| **Tag-baserad** | Applikationer , explicita utsläpp | | | låga | | | uppstartar |, | solo-devs | МSK5 | mogna lag |
| **Filiala-baserad** | Kontinuett utplacering | lågt | | | Start-up | МSK3 | snabbt |- | rörande lag |
| **GitFlow** | Regulerade versioner , flera versioner | | | Hög |
| **Trunk-based + Feature flags** | Höga -hastighetsteams | | | Medel || | stora tekniker | МSK4 | mogna nystartare
| **Monorepo multi-package** | Bibliotekar , gemensama kodexbaser | | | mellan | МSK3 | Plattenteams |

### Vad fungerar var

**Startups & Små lag**: Börja med tag-baserat eller ramverkt -baserad utnyttjandeM SK3 Säg det enkelt ♫ - du kan alltid lägga till komplexitet senare ♫. ♫ Trunk ♫

**Företagande**: Åtminstone kräver GitFlow eller liknande för noggrannhet , revīzijasspår M SK2 och utsläppshantering . Flera miljöer

**Enkel utvecklare**: etikett - baserat är idealt. trycka på etiketten

**Platform/Library Teams**: Bra monorepo-strategier med oberoende versionering per paket

## Tag-Based Deployment

Den enklaste och mest tillförlitliga strategin

### Miljötargetering

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

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

### Multi-Versionering av paket

För monorepos med flera publicierbara paket, använda tagpräfixer för att identifiera vilket paket man ska släppa

```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ända den hela tiden:

```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 automatiska versioneringar, [Minver](https://github.com/adamralph/minver) beräknar versioner från Git tags:

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

## Filiala-baserad utpostning

Deploy automatiskt när koden landar på specifika grannar

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

**Förmågor**: Inga manuella steg
**Olyckor**: Oavsiktliga utpostningar möjliga , mindre explicit historia

Jag använder ett hybridt tillvägagångssätt - bygga på branch-puss | ( | CI-bekräftelse |), | men publicera bara på tag |

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

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

## Auto-Aktualiseringar med observatori

För självständiga utpostningar [Observationstorn](https://containrrr.dev/watchtower/) drar automatiskt upp 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
```

**Deploymentflödet**: Att trycka på tag → GitHub Actions bygger | | → | Springa till registret |

## Kwaliteitssteg

Vinniga utspegningar är värdelösa om du utspegs bugs. Varje arbetsflöde bör inkludera 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 multi- -- -frameworkpaket - , -bygg alla mål - :

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

## Passwordless Publishing med OIDC

Modernt tillvägagångssätt - inga hemligheter för att rotera , inga nycklar för 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 utbyter sin OIDC-token för en kort NuGet API-kliv

## Tillförselkedjorskedjan

[Artifaktbescheinigunger](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) bevisa att dina artefakter är byggda i CI, inte manipulerade med

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

Konsumenter ser 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ån 3, använda [återanvändbara arbetsflöden](https://docs.github.com/en/actions/sharing-automations/reusing-workflows).

## Föreställ omgivningar

Teams behöver intressenter för att förutse förändringar innan de går samman

**Enterprise-metoden** - Filialen -grundade förfogningsmiljö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.
```

**Startup/solo-metod** - Tunnelera din lokala maskin

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

Eller använda [Kabelvakt](https://www.wireguard.com/) VPN för inre team-utgång till din dev-maskin.

## Praktiska tips

**Tag städ**: Git-tag står kvar för alltid

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

**Nameringskonventioner**: Var konsekvent

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

**Hemligheter**: Lagera i [GitHub Secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), aldrig i koden . Erforderliga hemligheter vanligtvis

- `DOCKER_HUB_ACCESS_TOKEN`
- `NUGET_API_KEY` ( eller använda OIDC
- `NPM_TOKEN`

**Monorepo-utveckling**: Använda projektreferenser under utvecklingen , byta till paketreferens för användningskontroll

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

## Gå till Kubernetes

Samma principer , olika verktyg

| Docker Compose | Kubernetes |
|----------------|------------|
| Tydtorn  | [ArgoCD](https://argo-cd.readthedocs.io/) / [Flux](https://fluxcd.io/docs/) |
| docker
| Kontineruppstartning | Rollingsoperation | |
| Handlig rollback | | | GitOps rollback

## sammanfattning

1. **Börja enkelt**: Tag-based deployment covers most needs
2. **Lägg till komplexitet när det behövs**: Filialen -baserade, flertalig
3. **Automatiserade kvalitet-grindar**: Test måste klaras innan de publiceras
4. **Aktivera rollback**: Timestamped-tag eller GitOps historia
5. **Bevara din pipeline**: OIDC för hemligheter
6. **Matcha din kontext**: Solo dev ≠ startup ≠ enterprise

De arbetsflödena som visas här körs i detta arkiv - check `.github/workflows/` för kompletta implementeringar.

**Kom ihåg**: Vinniga implementeringar är grunden till agil utveckling . Investera i din utsläppskedjor tidigt