Repository-Automatisierung einrichten
Rüsten Sie den vollständigen Stack aus Conventional Commits, Release-Please und CI-Automatisierung in jedem Repository auf. Funktioniert sowohl mit leeren Repositorys als auch mit Repositorys, die bereits Inhalt enthalten.
Übersicht
Shift Left: Fangen Sie Probleme so früh wie möglich ab. Eine schlechte Commit-Nachricht, die beim PR abgefangen wird, kostet Sekunden; dieselbe Nachricht, die in den Release-Notes landet, kostet Glaubwürdigkeit. Verlagern Sie die Validierung nach vorne – erzwingen Sie das Commit-Format bereits im PR-Titel, validieren Sie Konfigurationen in CI und fangen Sie Probleme ab, bevor sie in den Hauptzweig gelangen.
Schneller ist sicherer: Kleinere Batches und häufigere Releases verringern das Risiko. Ein Release mit 3 Änderungen ist einfacher zu debuggen als einer mit 30. Automatisierte Releases schaffen Vertrauen in den Release-Prozess selbst.
Diese Fähigkeit richtet den Durchsetzungsmechanismus ein: Die PR-Titelvalidierung stellt sicher, dass jeder Merge in den Hauptzweig eine aussagekräftige, parsebare Commit-Nachricht erzeugt. Release-Please wandelt diese Commits in automatisierte Releases mit Changelogs um. CI fängt Konfigurations- und Code-Probleme vor dem Merge ab.
Wann verwenden
- Ein neues Repository wird gestartet und benötigt von Anfang an Release-Automatisierung
- Ein bestehendes Repository hat keine automatisierte Versionierung oder Changelog-Generierung
- Migration von manuellen Release-Prozessen oder anderen Release-Tools
- Das Repository benötigt PR-Titelvalidierung und automatische Labelvergabe
Wann NICHT verwenden
- Das Repository hat bereits Release-Please oder eine gleichwertige Lösung konfiguriert (zuerst prüfen)
- Monorepo mit inkompatiblen Release-Tools (z.B. Lerna mit bereits funktionierender unabhängiger Versionierung)
- Das Repository ist ein Fork, bei dem der Upstream den Release-Prozess kontrolliert
Vorgehen
Schritt 1: Konfiguration sammeln
Fragen Sie den Benutzer nach diesen Werten, bevor Sie Dateien generieren:
| Parameter | Standard | Beschreibung |
|---|---|---|
PROJECT_NAME | (erforderlich) | Lesbarer Projektname für die Dokumentation |
INITIAL_VERSION | 0.1.0 | Start-Semantikversion |
RELEASE_TYPE | simple | simple (Einzelpaket) oder node / python / etc. |
REPO_LAYOUT | single | single (ein Paket im Stammverzeichnis) oder monorepo (mehrere Pakete) |
PACKAGE_PATHS | . | Für Monorepo: kommagetrennte Pfade wie packages/api,packages/ui |
DEPENDABOT_ECOSYSTEMS | github-actions | Kommagetrennt: github-actions, npm, pip, cargo, etc. |
DEFAULT_BRANCH | main | Branch, der Releases auslöst |
Den korrekten RELEASE_TYPE automatisch erkennen:
package.jsonvorhanden →nodevorschlagensetup.pyoderpyproject.tomlvorhanden →pythonvorschlagenCargo.tomlvorhanden →rustvorschlagen- Keines der oben genannten →
simplevorschlagen
Schritt 2: Vorhandene Dateien erkennen
Vor dem Erstellen von Dateien auf Konflikte prüfen:
for f in .github/workflows/pull-request.yml .github/workflows/main-branch.yml \
.github/release-please-config.json .release-please-manifest.json \
.github/dependabot.yml .github/pull_request_template.md docs/DEVELOPMENT.md; do
[[ -f "$f" ]] && echo "EXISTS: $f"
done
Wenn Dateien vorhanden sind, zeigen Sie einen Diff der Änderungen an und fragen Sie vor dem Überschreiben. Überschreiben Sie nicht stillschweigend – vorhandene Dateien können projektspezifische Anpassungen enthalten.
Schritt 3: Konfigurationsdateien erstellen
Erstellen Sie Dateien in dieser Reihenfolge (Abhängigkeiten fließen von oben nach unten):
3a. .github/release-please-config.json
Einzelpaket:
{
"release-type": "{{RELEASE_TYPE}}",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"initial-version": "{{INITIAL_VERSION}}",
"packages": {
".": {}
}
}
Monorepo: Ersetzen Sie packages durch einen Eintrag pro Pfad:
{
"packages": {
"packages/api": { "release-type": "node" },
"packages/ui": { "release-type": "node" }
}
}
Jedes Monorepo-Paket erhält einen eigenen release-type – fragen Sie den Benutzer pro Paket, wenn sie sich unterscheiden.
3b. .release-please-manifest.json
Einzelpaket:
{
".": "{{INITIAL_VERSION}}"
}
Monorepo: Ein Eintrag pro Paketpfad, jeder mit eigener Version.
3c. .github/workflows/pull-request.yml
name: Pull Request Validation
on:
pull_request:
types: [opened, edited, synchronize, reopened]
permissions:
pull-requests: write
contents: read
statuses: write
jobs:
validate-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
docs
chore
refactor
test
ci
requireScope: false
subjectPattern: ^[a-z].+$
subjectPatternError: |
The subject "{subject}" found in the pull request title "{title}"
didn't match the configured pattern. Please ensure that the subject
starts with a lowercase character (per conventional commits).
auto-label:
name: Auto Label PR
runs-on: ubuntu-latest
steps:
- name: Label based on PR title
uses: actions/github-script@v8
with:
script: |
const title = context.payload.pull_request.title;
const labelMap = {
'feat': 'enhancement',
'fix': 'bug',
'docs': 'documentation',
'chore': 'chore',
'refactor': 'refactor',
'test': 'test',
'ci': 'ci'
};
for (const [type, label] of Object.entries(labelMap)) {
if (title.startsWith(`${type}:`) || title.startsWith(`${type}(`)) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: [label]
});
break;
}
}
no-ai-attribution:
name: No AI Attribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Scan commit messages and PR body
env:
PR_BODY: ${{ github.event.pull_request.body }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Nur Trailer/Footer-Formen: Ein Commit, der Claude oder
# Anthropic nur im Fließtext erwähnt, ist in Ordnung. Menschliche Co-authored-by-Trailer sind in Ordnung.
PAT='^[[:space:]]*Co-authored-by:.*(Claude|Anthropic|noreply@anthropic)|Generated with \[?(Claude|Anthropic)'
fail=0
if git log --format='%B' "$BASE_SHA..$HEAD_SHA" | grep -Eiq "$PAT"; then
echo "::error::AI attribution found in a commit message on this branch"
fail=1
fi
if printf '%s' "$PR_BODY" | grep -Eiq "$PAT"; then
echo "::error::AI attribution found in the PR description"
fail=1
fi
[ "$fail" -eq 0 ] && echo "No AI attribution found."
exit $fail
ci-checks:
name: CI Checks
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- name: Validate YAML syntax
run: |
sudo apt-get update && sudo apt-get install -y yamllint
find . -name "*.yml" -o -name "*.yaml" | while read file; do
echo "Checking $file"
yamllint -d "{extends: default, rules: {line-length: disable}}" "$file" || true
done
No AI Attribution ist von Anfang an blockierend – es hat keine Falsch-Positiv-Oberfläche zu validieren (es erkennt Trailer- und Footer-Formen, nicht Fließtext), daher durchläuft es nicht den folgenden Graduierungspfad.
CI-Prüfungs-Graduierungspfad:
- Bereitstellung mit
continue-on-error: true(informativ, nicht blockierend) - Überprüfen, ob die Prüfungen bei 3-5 echten PRs bestehen
continue-on-errorentfernen und zu den erforderlichen Branch-Schutzprüfungen hinzufügen- Projektspezifische Prüfungen hinzufügen (Lint, Test, Build), wenn die Codebasis wächst
Keine Prüfung darf übersprungen werden. Wenn Lint fehlschlägt, beheben Sie den Lint-Fehler – deaktivieren Sie nicht die Regel. Wenn ein Test fehlschlägt, beheben Sie den Code – überspringen Sie den Test nicht. Wenn CI fehlschlägt, geben Sie die Fehlerausgabe an Ihren Agenten weiter und beheben Sie sie, bevor Sie erneut pushen.
3d. .github/workflows/main-branch.yml
name: Release Automation
on:
push:
branches:
- {{DEFAULT_BRANCH}}
permissions:
contents: write
pull-requests: write
jobs:
release-please:
name: Release Please
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: .github/release-please-config.json
manifest-file: .release-please-manifest.json
update-major-tag:
name: Update Major Version Tag
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.release-please.outputs.tag_name }}
- name: Update major version tag
env:
TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
run: |
MAJOR_TAG=$(echo "$TAG_NAME" | sed 's/^\(v[0-9]*\).*/\1/')
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -fa "$MAJOR_TAG" -m "Update $MAJOR_TAG tag to $TAG_NAME"
git push origin "$MAJOR_TAG" --force
3e. .github/dependabot.yml
Generieren Sie einen updates-Eintrag pro Ökosystem:
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
labels:
- "dependencies"
commit-message:
prefix: "chore"
include: "scope"
Die commit-message-Konfiguration stellt sicher, dass Dependabot-PRs automatisch den Conventional Commits entsprechen (z.B. chore(deps): bump actions/checkout from v5 to v6).
3f. .github/pull_request_template.md
## Was hat sich geändert
[Beschreiben Sie die Änderungen im Detail – dies fließt in das Changelog ein]
## Warum
[Kontext und Motivation für die Änderung]
## Checkliste
- [ ] PR-Titel entspricht dem Conventional-Commits-Format (`type: description`)
- [ ] Beschreibung erklärt das Was und Warum (nicht nur das Was)
- [ ] Keine Geheimnisse im Code, in Logs oder in der Versionskontrolle
- [ ] Tests laufen lokal erfolgreich
Der Abschnitt "Warum" ist entscheidend – PR-Beschreibungen, die nur sagen, was sich geändert hat, sind redundant zum Diff. Das Warum liefert den Kontext, der zukünftiges git-blame nützlich macht.
3g. .gitignore (falls nicht vorhanden)
Prüfen Sie, ob eine .gitignore existiert. Wenn nicht, erstellen Sie eine, die zum Projekt passt:
# Dependencies
node_modules/
# Build output
dist/
build/
.next/
# Environment
.env
.env.local
*.pem
# IDE
.idea/
# OS
.DS_Store
Thumbs.db
Passen Sie sie an den erkannten Stack an. Committen Sie niemals node_modules/, .env oder Build-Artefakte.
3h. docs/DEVELOPMENT.md
Generieren Sie einen Entwicklungsleitfaden, der Folgendes abdeckt:
- Branch-Workflow — Trunk-basierte Entwicklung: kurzlebige Feature-Branches (1-3 Tage), schnell zurückmergen. Branch-Namensgebung:
feature/<beschreibung>,fix/<beschreibung>,chore/<beschreibung>. - Commit-Disziplin — Innerhalb von Branches frei committen (jedes Format). Nur der PR-Titel zählt – er wird zur Squash-Merge-Commit-Nachricht im Hauptzweig und erscheint im Changelog.
- PR-Titelformat — Tabelle der Typen:
feat,fix,docs,chore,refactor,test,ci. Breaking Changes:feat!:oderBREAKING CHANGE:im Body. - Änderungsgröße — Ziel: ~100 Zeilen pro PR. ~300 für einzelne logische Änderungen akzeptabel. ~1000+ müssen aufgeteilt werden. Refactoring von Feature-Arbeit trennen – es sind unterschiedliche Änderungen.
- PR-Beschreibungen — Erste Zeile: kurz, imperativ, eigenständig. Body: Was sich ändert und warum. Anti-Patterns: "Fix bug", "Update file", "Phase 1".
- Automatisierte Prüfungen — PR-Titelvalidierung (erforderlich, blockiert Merge), automatische Labelvergabe (informativ), CI-Prüfungen (anfangs nicht blockierend, nach und nach erforderlich).
- Release-Prozess — Release-Please erstellt Release-PR → Merge → GitHub-Release + Tags + Changelog. Versionsverlauf: vor 1.0 (
feat→ Minor,fix→ Patch) vs. nach 1.0 (feat→ Minor,fix→ Patch,BREAKING CHANGE→ Major). - Fehlerbehebung — Häufige Probleme: PR-Titelvalidierung schlägt fehl (Titel bearbeiten), CI-Prüfungen schlagen fehl, Merge blockiert (erforderliche Statusüberprüfungen).
Verwenden Sie {{PROJECT_NAME}} in den Überschriften.
Schritt 4: Branch-Schutz-Empfehlungen
Nach der Dateierstellung präsentieren Sie diese als manuelle Schritte (nicht automatisch angewendet):
Empfohlene GitHub-Branch-Schutz-Einstellungen für {{DEFAULT_BRANCH}}:
✓ Pull-Request vor Merge erforderlich
✓ Statusprüfungen erforderlich: "Validate PR Title"
✓ Branches müssen auf dem neuesten Stand sein
✓ Nur Squash-Merge zulassen
✓ Lineare Historie erforderlich
Warum Squash-Merge: Die Branch-Historie (WIP-Commits, Fixups, Experimente) bleibt im PR erhalten. Der Hauptzweig erhält einen sauberen, aussagekräftigen, linearen Log, in dem jeder Commit ein Conventional Commit ist. Das macht Release-Please und git log --oneline nützlich.
Schritt 5: Workflow-Berechtigungen aktivieren
Release-Please benötigt die Berechtigung, Pull Requests über GitHub Actions zu erstellen. Diese ist standardmäßig deaktiviert bei neuen Repositorys und führt dazu, dass der Release-Automation-Workflow mit folgendem Fehler fehlschlägt:
GitHub Actions is not permitted to create or approve pull requests.
Weisen Sie den Benutzer an, diese Einstellung zu aktivieren:
GitHub Repo → Settings → Actions → General → Workflow permissions:
✓ Lese- und Schreibberechtigungen (erforderlich, damit Release-Please Changelog-Commits pushen kann)
✓ GitHub Actions erlauben, Pull Requests zu erstellen und zu genehmigen (erforderlich für Release-PRs)
Dieser Schritt muss vor dem ersten Push auf {{DEFAULT_BRANCH}} abgeschlossen sein, sonst schlägt Release-Please bei jedem Push fehl, bis er aktiviert ist.
Schritt 6: Überprüfen
# YAML-Syntax validieren
yamllint .github/workflows/*.yml .github/dependabot.yml
# JSON validieren
python3 -c "import json; ...
[…] forderung zur Übersetzung abgeschnitten]