Die vorherigen Kapitel haben GitHub Actions Stück für Stück aufgebaut: Workflows, Jobs, Secrets, Caching, Wiederverwendbarkeit, Deployment. Dieses Kapitel zeigt, wie alle Teile zusammenspielen. Am Ende steht ein vollständiges, produktionsreifes Repository mit allen Workflows, die ein Python-Projekt braucht.
Nach sieben Kapiteln sieht das badge-gen Repository so aus:
badge-gen/
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # Kontinuierliche Integration
│ │ ├── release.yml # Versionierung und Changelog
│ │ ├── publish.yml # PyPI-Veröffentlichung
│ │ └── pages.yml # GitHub Pages Deployment
│ ├── actions/
│ │ └── setup-python-env/
│ │ └── action.yml # Lokale Composite Action
│ ├── dependabot.yml # Automatische Updates
│ └── CODEOWNERS # Review-Zuständigkeiten
├── src/
│ └── badge_gen/
│ ├── __init__.py
│ ├── cli.py # Command-Line Interface
│ ├── generator.py # SVG-Generierung
│ └── metrics.py # Metrik-Sammlung
├── tests/
│ ├── __init__.py
│ ├── test_cli.py
│ ├── test_generator.py
│ └── test_metrics.py
├── pyproject.toml # Projekt-Konfiguration
├── README.md
├── CHANGELOG.md # Automatisch generiert
└── LICENSE
Dieser Workflow läuft bei jedem Push und Pull Request. Er stellt sicher, dass der Code funktioniert, bevor er gemerged wird.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install linters
run: pip install ruff mypy
- name: Ruff
run: ruff check src/ tests/
- name: Mypy
run: mypy src/ --ignore-missing-imports
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12']
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: pip install -e .[dev]
- name: Run tests
run: pytest --cov=src/badge_gen --cov-report=xml
- name: Upload coverage
if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install security tools
run: pip install bandit safety
- name: Bandit
run: bandit -r src/ -ll
- name: Safety
run: pip install -e . && safety checkWas passiert: Drei parallele Jobs prüfen Code-Qualität, Funktionalität und Sicherheit. Die Test-Matrix deckt 9 Kombinationen ab (3 Python-Versionen × 3 Betriebssysteme).
Dieser Workflow läuft bei Pushes auf main und erstellt automatisch neue Versionen basierend auf Conventional Commits.
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
outputs:
skipped: ${{ steps.changelog.outputs.skipped }}
tag: ${{ steps.changelog.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Conventional Changelog
id: changelog
uses: TriPSs/conventional-changelog-action@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version-file: pyproject.toml
version-path: project.version
skip-on-empty: 'true'
git-push: 'true'
- name: Create GitHub Release
if: ${{ steps.changelog.outputs.skipped == 'false' }}
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.changelog.outputs.tag }}
body: ${{ steps.changelog.outputs.clean_changelog }}Was passiert: Der Workflow analysiert
Commit-Messages seit dem letzten Tag. Bei feat: erhöht er
die Minor-Version, bei fix: die Patch-Version, bei
BREAKING CHANGE die Major-Version. CHANGELOG.md wird
aktualisiert, ein Tag erstellt und ein GitHub Release
veröffentlicht.
Dieser Workflow wird durch neue Releases getriggert und veröffentlicht das Paket auf PyPI.
# .github/workflows/publish.yml
name: Publish to PyPI
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install build tools
run: pip install build
- name: Build
run: python -m build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
test-install:
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install from wheel
run: pip install dist/*.whl
- name: Verify installation
run: badge-gen --version
publish:
needs: test-install
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/badge-gen/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1Was passiert: Der Workflow baut das Paket, testet
die Installation auf verschiedenen Python-Versionen und veröffentlicht
dann via Trusted Publishing auf PyPI. Das pypi Environment
erfordert manuelle Genehmigung.
Dieser Workflow läuft bei Pushes auf main und deployed generierte Badges auf GitHub Pages.
# .github/workflows/pages.yml
name: GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: Install badge-gen
run: pip install -e .
- name: Generate badges
run: |
mkdir -p _site/badges
badge-gen create --name "build" --value "passing" --color "brightgreen" -o _site/badges/build.svg
badge-gen create --name "coverage" --value "87%" --color "yellow" -o _site/badges/coverage.svg
badge-gen create --name "license" --value "MIT" --color "blue" -o _site/badges/license.svg
badge-gen create --name "python" --value "3.10 | 3.11 | 3.12" --color "blue" -o _site/badges/python.svg
- name: Generate index
run: |
cat > _site/index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>badge-gen Showcase</title>
<style>
body { font-family: system-ui; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
h1 { color: #333; }
.badge { margin: 0.5rem 0; }
code { background: #f4f4f4; padding: 0.2rem 0.4rem; border-radius: 3px; }
</style>
</head>
<body>
<h1>badge-gen Showcase</h1>
<p>Diese Badges wurden automatisch generiert.</p>
<h2>Verfügbare Badges</h2>
<div class="badge"><img src="badges/build.svg" alt="Build"></div>
<div class="badge"><img src="badges/coverage.svg" alt="Coverage"></div>
<div class="badge"><img src="badges/license.svg" alt="License"></div>
<div class="badge"><img src="badges/python.svg" alt="Python"></div>
<h2>Verwendung</h2>
<pre><code>pip install badge-gen
badge-gen create --name "status" --value "online" --color "green"</code></pre>
</body>
</html>
EOF
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: _site
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4Was passiert: Der Workflow installiert badge-gen aus dem aktuellen Repository, generiert Beispiel-Badges und deployed sie auf GitHub Pages.
Tag 1: Feature entwickeln
# Neuen Branch erstellen
git checkout -b feature/add-gradient-badges
# Code schreiben, testen
# ...
# Commit mit Conventional Commits
git add .
git commit -m "feat: add gradient background support"
# Push löst CI aus
git push origin feature/add-gradient-badgesTag 2: Pull Request
Automatisch nach Merge:
feat: Commit
→ Version 1.3.0 → Tag → GitHub ReleaseErgebnis: Ein Commit-Message wie
feat: add gradient background support führt automatisch zu
einer neuen Version auf PyPI und aktualisierten Badges auf GitHub
Pages.
# .github/dependabot.yml
version: 2
updates:
# Python Dependencies
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "deps"
labels:
- "dependencies"
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "ci"
labels:
- "ci"Was passiert: Dependabot erstellt wöchentlich PRs für veraltete Dependencies – sowohl Python-Pakete als auch Actions. Die PRs durchlaufen automatisch den CI-Workflow.
# .github/CODEOWNERS
# Diese Datei definiert, wer Reviews für welche Dateien durchführen muss
# Workflow-Änderungen brauchen DevOps-Review
.github/workflows/ @my-org/devops-team
# Python-Code braucht Maintainer-Review
src/ @my-org/maintainers
tests/ @my-org/maintainers
# Dokumentation kann jeder reviewen
*.md @my-org/contributors
Repository Settings → Environments:
| Environment | Protection Rules | Secrets |
|---|---|---|
github-pages |
Deployment branches: main | – |
pypi |
Required reviewers: 1, Deployment branches: main | – (Trusted Publishing) |
testpypi |
Deployment branches: main, develop | – (Trusted Publishing) |
Beim Start eines neuen Projekts mit GitHub Actions:
GitHub zeigt Laufzeiten im Actions-Tab. Bei Problemen:
Repository → Actions → [Workflow] → Workflow runs
Typische Warnsignale:
Organization → Settings → Billing → Actions
Kostenoptimierung:
paths-ignore für irrelevante ÄnderungenGitHub-native:
Settings → Notifications → Actions → "Send notifications for workflow runs on watched repositories"
Slack-Integration:
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
channel-id: 'builds'
slack-message: "❌ ${{ github.workflow }} failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}| Aufgabe | Frequenz | Wie |
|---|---|---|
| Dependabot-PRs reviewen | Wöchentlich | PRs mit Label dependencies |
| Action-Versionen prüfen | Monatlich | SHA-Pinning aktualisieren |
| Workflow-Laufzeiten prüfen | Monatlich | Actions-Tab analysieren |
| Unused Secrets aufräumen | Quartalsweise | Settings → Secrets |
| Environment-Konfiguration prüfen | Quartalsweise | Settings → Environments |
Ursache: Unterschiedliche Umgebungen.
Lösung: act für lokale Tests nutzen
(siehe Kapitel 4) oder CI-Umgebung genau dokumentieren.
Checkliste:
.github/workflows/?actionlint nutzen)on: prüfen)paths / paths-ignore blockiert?Checkliste:
Checkliste:
hashFiles() findet die Datei?Checkliste:
Nach diesem Kapitel haben wir ein vollständiges CI/CD-Setup:
Was wir erreicht haben:
Ein Developer muss nur noch gute Commits schreiben – der Rest passiert automatisch.