Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
74f5691e27 | |||
aa25ceb957
|
|||
cda07a61f7 | |||
8d5f168a10
|
|||
910f1d6eed | |||
de05716b07
|
|||
1986083586 | |||
e875e781a7
|
|||
c06d22e124 | |||
81b2339ea6
|
|||
9f3f60fbf2 | |||
45a61134d6
|
|||
7720343173 | |||
e4785769ea
|
|||
9494fa3619 | |||
8b3117fdca
|
|||
8ff8a04437 | |||
e5ac928fd4
|
|||
db8fda15df
|
|||
f570a3700b | |||
a9ed247cb4
|
|||
579c70b784
|
|||
6c18e41b00 | |||
3f5c2cec4f | |||
![]() |
7f4c75e606 | ||
a6dde44a84 | |||
5cc850b8a9 | |||
ad14e31b75 | |||
22972d578c | |||
a48f4638c0 | |||
b50de01653 | |||
888acd355f | |||
92b4d3872f | |||
b4702c1a72 | |||
aec4c78c6a | |||
59ac01451f |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
50
.gitea/COMMIT_GPT.md
Normal file
50
.gitea/COMMIT_GPT.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# GPT Prompt
|
||||
|
||||
This is a prompt for a GPT model to generate a commit message based on the changes made in the code.
|
||||
|
||||
```plaintext
|
||||
# System
|
||||
You are a highly precise Git commit message generator for changelog-driven repositories.
|
||||
Your only task is to read the provided multi-file git diff and generate **one and only one** Conventional Commit message that strictly complies with the rules below.
|
||||
|
||||
# Language
|
||||
You MUST write the entire message in English only.
|
||||
|
||||
# Commit Rules
|
||||
|
||||
1. Use exactly one of the following lowercase types:
|
||||
feat, fix, docs, style, refactor, perf, test, chore, revert
|
||||
|
||||
2. Optionally add a `(<scope>)` after the type:
|
||||
• Use a short lowercase identifier (e.g., directory, module, file group)
|
||||
• Omit if no dominant scope exists
|
||||
|
||||
3. Follow this structure:
|
||||
`type(scope): summary`
|
||||
• The summary must be in imperative mood
|
||||
• Max 72 characters
|
||||
• No trailing period
|
||||
• Must not contain emojis or casing deviations
|
||||
|
||||
4. If the body is needed:
|
||||
• Add exactly one blank line after the subject
|
||||
• Use `- ` bullet points
|
||||
• Each line must be ≤ 72 characters
|
||||
• Explain what was changed and (if shown in the diff) why
|
||||
|
||||
5. Do NOT include:
|
||||
• `BREAKING CHANGE:` or any `!` markers
|
||||
• PR numbers, issue IDs, author names, ticket references
|
||||
• Markdown formatting, emojis, or code blocks
|
||||
|
||||
6. The following `chore(...)` patterns MUST be ignored and skipped from changelogs:
|
||||
chore(changelog), chore(version), chore(release): prepare for, chore(deps), chore(pr), chore(pull)
|
||||
|
||||
7. If the commit body contains the word `security`, it will be classified as security-relevant (🛡️), regardless of type.
|
||||
|
||||
8. Output MUST consist only of the final commit message, as plain text.
|
||||
No extra prose, no explanation, no formatting, no examples.
|
||||
|
||||
# Now, read the diff and generate the message.
|
||||
Output only the valid Conventional Commit message, exactly.
|
||||
```
|
198
.gitea/HOWTO_RELEASE.md
Normal file
198
.gitea/HOWTO_RELEASE.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 📦 HOWTO: Release erstellen mit Auto-Changelog-Workflow
|
||||
|
||||
Dieses Repository nutzt einen automatisierten CI/CD-Workflow zur **Versionsverwaltung, Changelog-Generierung und Release-Erstellung**.
|
||||
Der gesamte Prozess ist deklarativ und läuft automatisch – ausgelöst durch Änderungen an einer Datei: `VERSION`.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Was passiert automatisch?
|
||||
|
||||
Sobald Änderungen in `main` landen, prüft der Workflow:
|
||||
|
||||
- 🔍 **Hat sich die Datei `VERSION` geändert?**
|
||||
- ❌ **Nein** → es wird nur das `CHANGELOG.md` aktualisiert (unreleased Abschnitt)
|
||||
- ✅ **Ja** → es wird:
|
||||
- ein vollständiger Changelog für diese Version erzeugt
|
||||
- ein Git-Tag `vX.Y.Z` erstellt
|
||||
- ein Release in Gitea veröffentlicht (inkl. Beschreibung aus dem Changelog)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Wie erzeuge ich ein Release?
|
||||
|
||||
### 1. Erhöhe die Version in der Datei `VERSION`
|
||||
|
||||
Beispiel:
|
||||
|
||||
```txt
|
||||
1.2.3
|
||||
```
|
||||
|
||||
> Diese Datei muss **als eigene Commit-Änderung** erfolgen – idealerweise als letzter Commit in einem PR.
|
||||
> Die Commit-Nachricht sollte mit `chore(version)` beginnen, damit dieser nicht im Changelog auftaucht.
|
||||
|
||||
---
|
||||
|
||||
### 2. Mergen in `main`
|
||||
|
||||
Sobald `main` den Commit mit neuer `VERSION` enthält, wird automatisch:
|
||||
|
||||
- das `CHANGELOG.md` regeneriert und committed
|
||||
- der neue Git-Tag erstellt (`v1.2.3`)
|
||||
- ein Gitea Release mit genau diesem Changelog erzeugt
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Hinweis zu Tokens & Webhooks
|
||||
|
||||
Damit das Release auch korrekt weitere Workflows auslösen kann (z. B. über `on: release`), ist **ein Personal Access Token notwendig**.
|
||||
|
||||
### 🔐 Secret: `RELEASE_PUBLISH_TOKEN`
|
||||
|
||||
> Lege ein Repository-Secret mit diesem Namen an.
|
||||
> Es sollte ein **Gitea Personal Access Token** mit folgenden Berechtigungen sein:
|
||||
|
||||
- `write:repo`
|
||||
- `write:release`
|
||||
- idealerweise: keine Ablaufzeit
|
||||
|
||||
Wird dieser Token **nicht** gesetzt, fällt der Workflow auf `ACTIONS_RUNTIME_TOKEN` zurück, aber:
|
||||
- Release wird trotzdem erstellt
|
||||
- **⚠️ andere Workflows, die auf `release.published` reagieren, könnten nicht getriggert werden**
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Debugging-Tipps
|
||||
|
||||
- Stelle sicher, dass `VERSION` exakt **eine gültige neue semver-Version** enthält
|
||||
- Achte auf den Commit-Log: Changelog-Commits sind mit `chore(changelog):` gekennzeichnet
|
||||
- Verwende nur `main` als Trigger-Zweig
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Erweiterung
|
||||
|
||||
In `upload-assets.yml` kannst du beliebige Build-Artefakte automatisch an das Release anhängen, sobald es veröffentlicht ist.
|
||||
|
||||
Dafür:
|
||||
- liegt das Script `.gitea/scripts/get-release-id.sh`
|
||||
- sowie `.gitea/scripts/upload-asset.sh` bereit
|
||||
|
||||
Mehr dazu in der Datei: `.gitea/workflows/upload-assets.yml`
|
||||
|
||||
---
|
||||
|
||||
## 🧘 Best Practice
|
||||
|
||||
- Changelog-Generierung nie manuell ausführen
|
||||
- Nur `VERSION` ändern, um ein neues Release auszulösen
|
||||
- Auf `CHANGELOG.md` nie direkt committen
|
||||
- Release-Daten niemals per Hand in Gitea pflegen
|
||||
|
||||
📎 Alles wird versioniert, automatisiert und reproduzierbar erzeugt.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Commit-Gruppierung & Changelog-Erzeugung
|
||||
|
||||
Der Changelog wird auf Basis definierter **Commit-Gruppen** erzeugt.
|
||||
Diese Regeln sind in `cliff.toml` unter `commit_parsers` konfiguriert.
|
||||
|
||||
| Prefix / Muster | Gruppe | Beschreibung |
|
||||
|-------------------------------|---------------------------|--------------------------------------------------|
|
||||
| `feat:` | 🚀 Features | Neue Funktionalität |
|
||||
| `fix:` | 🐛 Bug Fixes | Fehlerbehebungen |
|
||||
| `doc:` | 📚 Documentation | Änderungen an Doku, Readmes etc. |
|
||||
| `perf:` | ⚡ Performance | Leistungsverbesserungen |
|
||||
| `refactor:` | 🚜 Refactor | Reorganisation ohne Verhaltensänderung |
|
||||
| `style:` | 🎨 Styling | Formatierung, Whitespaces, Code-Style |
|
||||
| `test:` | 🧪 Testing | Neue oder angepasste Tests |
|
||||
| `ci:` oder `chore:` (ohne Spezifizierung) | ⚙️ Miscellaneous Tasks | CI-Änderungen, Aufgaben, Wartung etc. |
|
||||
| `chore(changelog)`, `chore(version)`, `chore(release): prepare for`, `chore(deps...)`, `chore(pr)`, `chore(pull)` | *(ignoriert)* | Diese Commits werden im Changelog **ausgelassen** |
|
||||
| Commit-Body enthält `security` | 🛡️ Security | Sicherheitsrelevante Änderungen |
|
||||
| `revert:` | ◀️ Revert | Rückgängig gemachte Commits |
|
||||
| alles andere | 💼 Other | Fallback für nicht erkannte Formate |
|
||||
|
||||
### ✍️ Beispiel:
|
||||
|
||||
```bash
|
||||
git commit -m "feat: add login endpoint"
|
||||
git commit -m "fix: prevent crash on null input"
|
||||
git commit -m "chore(version): bump to 1.2.3"
|
||||
```
|
||||
|
||||
> Nur die ersten beiden erscheinen im Changelog – der dritte wird **automatisch übersprungen**.
|
||||
|
||||
---
|
||||
|
||||
## 🧾 Umgang mit `CHANGELOG.md` beim Mergen und Releasen
|
||||
|
||||
Wenn du automatisiert einen Changelog mit `git-cliff` erzeugst, ist `CHANGELOG.md` ein **generiertes Artefakt** – und kein handgepflegter Quelltext.
|
||||
|
||||
Beim Mergen von Feature-Branches in `main` kann es deshalb zu **unnötigen Konflikten** in dieser Datei kommen, obwohl der Inhalt später sowieso neu erzeugt wird.
|
||||
|
||||
---
|
||||
|
||||
## 🧼 Umgang mit `CHANGELOG.md` in Feature-Branches
|
||||
|
||||
Wenn du mit **Feature-Branches** arbeitest, wird `CHANGELOG.md` dort oft automatisch erzeugt.
|
||||
Das kann beim späteren Merge in `main` zu **unnötigen Merge-Konflikten** führen.
|
||||
|
||||
### ✅ Empfohlene Vorgehensweise
|
||||
|
||||
**Bevor du den Branch mit `main` zusammenführst** (Merge oder Cherry-Pick):
|
||||
|
||||
```bash
|
||||
git rm CHANGELOG.md
|
||||
git commit -m "chore(changelog): remove generated CHANGELOG.md before merge"
|
||||
git push
|
||||
```
|
||||
|
||||
Dadurch:
|
||||
|
||||
* verhinderst du Merge-Konflikte mit `CHANGELOG.md`
|
||||
* wird die Datei bei Feature-Branches nicht mehr automatisch erzeugt
|
||||
* bleibt deine Historie sauber und konfliktfrei
|
||||
|
||||
> 💡 Der Workflow erzeugt `CHANGELOG.md` automatisch **nur**, wenn:
|
||||
>
|
||||
> * die Datei schon vorhanden ist **oder**
|
||||
> * der Branch `main` heißt
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Merge-Konflikte verhindern mit `.gitattributes`
|
||||
|
||||
Damit Git bei Konflikten in `CHANGELOG.md` **automatisch deine Version bevorzugt**, kannst du folgende Zeile in die Datei `.gitattributes` aufnehmen:
|
||||
|
||||
```gitattributes
|
||||
CHANGELOG.md merge=ours
|
||||
```
|
||||
|
||||
Das bedeutet:
|
||||
|
||||
* Beim Merge wird die Version aus dem aktuellen Branch (`ours`) behalten
|
||||
* Änderungen aus dem Ziel-Branch (`theirs`) werden verworfen
|
||||
|
||||
### ✅ So verwendest du es richtig:
|
||||
|
||||
1. **Füge die Regel in `main` hinzu**:
|
||||
|
||||
```bash
|
||||
echo "CHANGELOG.md merge=ours" >> .gitattributes
|
||||
git add .gitattributes
|
||||
git commit -m "chore(git): prevent merge conflicts in CHANGELOG.md"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
2. **Hole sie in deinen Feature-Branch**:
|
||||
|
||||
```bash
|
||||
git checkout feature/xyz
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
3. **Ab sofort werden Konflikte in `CHANGELOG.md` automatisch aufgelöst** – lokal.
|
||||
|
||||
> ⚠️ Hinweis: Plattformen wie **Gitea, GitHub oder GitLab ignorieren `.gitattributes` beim Merge über die Web-Oberfläche**.
|
||||
> Führe Merges daher **lokal** durch, wenn du Konflikte verhindern willst.
|
45
.gitea/scripts/cleanup_versions.sh
Executable file
45
.gitea/scripts/cleanup_versions.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# cleanup_dev_versions.sh - Delete old PyPI dev versions from Gitea package registry
|
||||
|
||||
# Required environment variables
|
||||
USERNAME="${TWINE_USERNAME}"
|
||||
TOKEN="${TWINE_PASSWORD}"
|
||||
REPO="${GITHUB_REPOSITORY}" # e.g., maxp/repocat
|
||||
API_BASE="${GITHUB_API_URL%/}" # Strip trailing slash if present
|
||||
|
||||
OWNER="${REPO%%/*}"
|
||||
PACKAGE_NAME="${REPO##*/}"
|
||||
API_URL="${API_BASE}/packages/${OWNER}/pypi/${PACKAGE_NAME}"
|
||||
|
||||
# Fetch the list of versions
|
||||
response=$(curl -s -u "$USERNAME:$TOKEN" "$API_URL")
|
||||
|
||||
# Extract all .dev versions, sort by creation time
|
||||
mapfile -t versions_to_delete < <(echo "$response" | jq -r '
|
||||
map(select(.version | test("\\.dev"))) |
|
||||
sort_by(.created_at) |
|
||||
.[0:-1][] |
|
||||
.version')
|
||||
|
||||
# Determine latest version to keep
|
||||
latest_version=$(echo "$response" | jq -r '
|
||||
map(select(.version | test("\\.dev"))) |
|
||||
sort_by(.created_at) |
|
||||
last.version')
|
||||
|
||||
if [[ -z "$latest_version" || ${#versions_to_delete[@]} -eq 0 ]]; then
|
||||
echo "No old .dev versions to delete."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Keeping latest .dev version: $latest_version"
|
||||
|
||||
# Delete old .dev versions
|
||||
for version in "${versions_to_delete[@]}"; do
|
||||
echo "Deleting old .dev version: $version"
|
||||
curl -s -X DELETE -u "$USERNAME:$TOKEN" "$API_URL/$version"
|
||||
done
|
||||
|
||||
echo "Cleanup complete."
|
21
.gitea/scripts/get-release-id.sh
Executable file
21
.gitea/scripts/get-release-id.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Eingaben
|
||||
TAG="$1"
|
||||
TOKEN="${ACTIONS_RUNTIME_TOKEN:-<fallback_token>}"
|
||||
REPO="${GITHUB_REPOSITORY:-owner/example}"
|
||||
API="${GITHUB_API_URL:-https://gitea.example.tld/api/v1}"
|
||||
|
||||
OWNER=$(echo "$REPO" | cut -d/ -f1)
|
||||
NAME=$(echo "$REPO" | cut -d/ -f2)
|
||||
|
||||
RESPONSE=$(curl -sf \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
"$API/repos/$OWNER/$NAME/releases/tags/$TAG")
|
||||
|
||||
RELEASE_ID=$(echo "$RESPONSE" | jq -r '.id')
|
||||
echo "Release-ID für $TAG ist: $RELEASE_ID"
|
||||
|
||||
# Für GitHub Actions als Umgebungsvariable
|
||||
echo "GT_RELEASE_ID=$RELEASE_ID" >> "$GITHUB_ENV"
|
14
.gitea/scripts/set_poetry_version.sh
Executable file
14
.gitea/scripts/set_poetry_version.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASE_VERSION=$(cat VERSION)
|
||||
NIGHTLY_SUFFIX=""
|
||||
|
||||
if [[ "$1" == "nightly" ]]; then
|
||||
# Beispiel: 20240511.1358 → 11. Mai, 13:58 Uhr
|
||||
NIGHTLY_SUFFIX=".dev$(date +%Y%m%d%H%M)"
|
||||
fi
|
||||
|
||||
FULL_VERSION="${BASE_VERSION}${NIGHTLY_SUFFIX}"
|
||||
|
||||
echo "Using version: $FULL_VERSION"
|
||||
poetry version "$FULL_VERSION"
|
40
.gitea/scripts/upload-asset.sh
Executable file
40
.gitea/scripts/upload-asset.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Eingabeparameter
|
||||
FILE_PATH="$1" # z. B. ./dist/build.zip
|
||||
CUSTOM_NAME="${2:-}" # optional: anderer Name unter dem das Asset gespeichert werden soll
|
||||
RELEASE_ID="${GT_RELEASE_ID:-}" # aus Umgebung
|
||||
|
||||
# Validierung
|
||||
if [[ -z "$RELEASE_ID" ]]; then
|
||||
echo "❌ RELEASE_ID ist nicht gesetzt. Abbruch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$FILE_PATH" ]]; then
|
||||
echo "❌ Datei '$FILE_PATH' existiert nicht. Abbruch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default-Konfiguration
|
||||
TOKEN="${ACTIONS_RUNTIME_TOKEN:-<fallback_token>}"
|
||||
REPO="${GITHUB_REPOSITORY:-owner/example}"
|
||||
API="${GITHUB_API_URL:-https://gitea.example.tld/api/v1}"
|
||||
|
||||
# Owner/Repo auflösen
|
||||
OWNER=$(echo "$REPO" | cut -d/ -f1)
|
||||
NAME=$(echo "$REPO" | cut -d/ -f2)
|
||||
|
||||
# Dateiname setzen
|
||||
FILENAME="${CUSTOM_NAME:-$(basename "$FILE_PATH")}"
|
||||
|
||||
echo "🔼 Uploading '$FILE_PATH' as '$FILENAME' to release ID $RELEASE_ID"
|
||||
|
||||
# Upload
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
-F "attachment=@$FILE_PATH" \
|
||||
"$API/repos/$OWNER/$NAME/releases/$RELEASE_ID/assets?name=$FILENAME"
|
||||
|
||||
echo "✅ Upload abgeschlossen: $FILENAME"
|
62
.gitea/workflows/build-and-deploy-nightly.yml
Normal file
62
.gitea/workflows/build-and-deploy-nightly.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Build and Publish nightly package
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- 'CHANGELOG.md'
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🐍 Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: 🔄 Restore cache
|
||||
uses: https://git.0xmax42.io/actions/cache@v1
|
||||
with:
|
||||
key: poetry-v1-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
|
||||
paths: |
|
||||
~/.cache/pypoetry
|
||||
~/.cache/pip
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
pip install poetry
|
||||
|
||||
- name: Install Project Dependencies
|
||||
working-directory: .
|
||||
run: |
|
||||
poetry install
|
||||
|
||||
- name: Set version from VERSION file (with nightly suffix)
|
||||
run: ./.gitea/scripts/set_poetry_version.sh nightly
|
||||
|
||||
- name: Build Package
|
||||
working-directory: .
|
||||
run: |
|
||||
poetry build
|
||||
|
||||
- name: Publish to Gitea Package Registry
|
||||
working-directory: .
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||
run: |
|
||||
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
||||
|
||||
- name: Cleanup old dev versions
|
||||
run: |
|
||||
.gitea/scripts/cleanup_versions.sh '\.dev'
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
76
.gitea/workflows/build-and-deploy-release.yml
Normal file
76
.gitea/workflows/build-and-deploy-release.yml
Normal file
@@ -0,0 +1,76 @@
|
||||
name: Build and Publish nightly package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: 🐍 Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: 🔄 Restore cache
|
||||
uses: https://git.0xmax42.io/actions/cache@v1
|
||||
with:
|
||||
key: poetry-v1-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
|
||||
paths: |
|
||||
~/.cache/pypoetry
|
||||
~/.cache/pip
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
pip install poetry
|
||||
|
||||
- name: Install Project Dependencies
|
||||
working-directory: .
|
||||
run: |
|
||||
poetry install
|
||||
|
||||
- name: Build Package
|
||||
working-directory: .
|
||||
run: |
|
||||
poetry build
|
||||
|
||||
- name: Get built wheel filename
|
||||
id: get_whl
|
||||
run: |
|
||||
echo "whl_file=$(basename dist/*.whl)" >> $GITHUB_OUTPUT
|
||||
echo "sdist_file=$(basename dist/*.tar.gz)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish to Gitea Package Registry
|
||||
working-directory: .
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||
run: |
|
||||
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
||||
|
||||
- name: Get Release ID from tag
|
||||
run: .gitea/scripts/get-release-id.sh "${{ github.event.release.tag_name }}"
|
||||
|
||||
- name: Upload assets
|
||||
run: |
|
||||
.gitea/scripts/upload-asset.sh ./dist/${{ steps.get_whl.outputs.whl_file }}
|
||||
.gitea/scripts/upload-asset.sh ./dist/${{ steps.get_whl.outputs.sdist_file }}
|
||||
|
||||
- name: Run Releases Sync Action
|
||||
uses: https://git.0xmax42.io/actions/releases-sync@main
|
||||
with:
|
||||
gitea_token: $ACTIONS_RUNTIME_TOKEN
|
||||
gitea_url: https://git.0xmax42.io
|
||||
gitea_owner: maxp
|
||||
gitea_repo: ait
|
||||
tag_name: ${{ inputs.tag || github.event.release.tag_name }}
|
||||
github_token: ${{ secrets.SYNC_GITHUB_TOKEN }}
|
||||
github_owner: 0xMax42
|
||||
github_repo: ait
|
223
.gitea/workflows/release.yml
Normal file
223
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,223 @@
|
||||
name: Auto Changelog & Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "**"
|
||||
|
||||
jobs:
|
||||
detect-version-change:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version_changed: ${{ steps.set.outputs.version_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check if VERSION file changed
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
echo "🔍 Vergleich mit github.event.before:"
|
||||
echo "Before: ${{ github.event.before }}"
|
||||
echo "After: ${{ github.sha }}"
|
||||
|
||||
echo "📄 Changed files between before and after:"
|
||||
git diff --name-only ${{ github.event.before }} ${{ github.sha }} || echo "(diff failed)"
|
||||
|
||||
if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^VERSION$'; then
|
||||
echo "✅ VERSION file was changed"
|
||||
echo "VERSION_CHANGED=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "ℹ️ VERSION file not changed"
|
||||
echo "VERSION_CHANGED=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set output (always)
|
||||
id: set
|
||||
run: |
|
||||
echo "version_changed=${VERSION_CHANGED:-false}" >> $GITHUB_OUTPUT
|
||||
|
||||
changelog-only:
|
||||
needs: detect-version-change
|
||||
if: github.ref != 'refs/heads/main' || needs.detect-version-change.outputs.version_changed == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set Git Author
|
||||
run: |
|
||||
git config user.name "$CI_COMMIT_AUTHOR_NAME"
|
||||
git config user.email "$CI_COMMIT_AUTHOR_EMAIL"
|
||||
|
||||
- name: Read CLIFF_VERSION from cliff.toml
|
||||
id: cliff_version
|
||||
run: |
|
||||
echo "version=$(awk -F '=' '/^# CLIFF_VERSION=/ { gsub(/[" ]/, "", $2); print $2 }' cliff.toml)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore git-cliff cache
|
||||
id: restore-cliff
|
||||
uses: https://git.0xmax42.io/actions/cache@v1
|
||||
with:
|
||||
key: cargo-cliff-${{ steps.cliff_version.outputs.version }}
|
||||
paths: |
|
||||
/root/.cargo/bin
|
||||
|
||||
- name: Install git-cliff
|
||||
if: steps.restore-cliff.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cargo install git-cliff --locked --version "${{ steps.cliff_version.outputs.version }}" --features gitea
|
||||
|
||||
- name: Generate unreleased changelog (if file exists or on main)
|
||||
run: |
|
||||
if [[ -f CHANGELOG.md || "${GITHUB_REF##refs/heads/}" == "main" ]]; then
|
||||
echo "Generating CHANGELOG.md..."
|
||||
git-cliff -c cliff.toml -o CHANGELOG.md
|
||||
else
|
||||
echo "CHANGELOG.md does not exist and this is not 'main'. Skipping generation."
|
||||
fi
|
||||
|
||||
- name: Commit updated CHANGELOG
|
||||
run: |
|
||||
git add CHANGELOG.md
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "chore(changelog): update unreleased changelog"
|
||||
git push origin "${GITHUB_REF##refs/heads/}"
|
||||
fi
|
||||
|
||||
release:
|
||||
needs: detect-version-change
|
||||
if: needs.detect-version-change.outputs.version_changed == 'true' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set Git Author
|
||||
run: |
|
||||
git config user.name "$CI_COMMIT_AUTHOR_NAME"
|
||||
git config user.email "$CI_COMMIT_AUTHOR_EMAIL"
|
||||
|
||||
- name: Read VERSION
|
||||
id: version
|
||||
run: echo "value=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Read CLIFF_VERSION from cliff.toml
|
||||
id: cliff_version
|
||||
run: |
|
||||
echo "version=$(awk -F '=' '/^# CLIFF_VERSION=/ { gsub(/[" ]/, "", $2); print $2 }' cliff.toml)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore git-cliff cache
|
||||
id: restore-cliff
|
||||
uses: https://git.0xmax42.io/actions/cache@v1
|
||||
with:
|
||||
key: cargo-cliff-${{ steps.cliff_version.outputs.version }}
|
||||
paths: |
|
||||
/root/.cargo/bin
|
||||
|
||||
- name: Install git-cliff
|
||||
if: steps.restore-cliff.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cargo install git-cliff --locked --version "${{ steps.cliff_version.outputs.version }}" --features gitea
|
||||
|
||||
- name: Generate changelog for release and tag
|
||||
id: generate-changelog
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.value }}
|
||||
git-cliff -c cliff.toml -t "v$VERSION" -o CHANGELOG.md
|
||||
|
||||
BODY=$(mktemp)
|
||||
ESCAPED_VERSION=$(echo "$VERSION" | sed 's/\./\\./g')
|
||||
|
||||
awk -v ver="$ESCAPED_VERSION" '
|
||||
$0 ~ "^## \\[" ver "\\]" {
|
||||
print_flag=1
|
||||
line = $0
|
||||
sub(/^## /, "", line)
|
||||
sub(/\\s*\\(.*\\)/, "", line) # entfernt z. B. "(...)" oder "(*)"
|
||||
print line
|
||||
next
|
||||
}
|
||||
$0 ~ "^## \\[" && $0 !~ "^## \\[" ver "\\]" {
|
||||
print_flag=0
|
||||
}
|
||||
print_flag
|
||||
' CHANGELOG.md > "$BODY"
|
||||
|
||||
echo "changelog_body_path=$BODY" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit updated CHANGELOG
|
||||
run: |
|
||||
git add CHANGELOG.md
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "chore(changelog): update changelog for v${{ steps.version.outputs.value }}"
|
||||
git push origin main
|
||||
fi
|
||||
|
||||
- name: Create Git tag (if not exists)
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.value }}
|
||||
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
|
||||
echo "Tag v$VERSION already exists, skipping tag creation."
|
||||
else
|
||||
export GIT_AUTHOR_DATE="$(date --iso-8601=seconds)"
|
||||
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
|
||||
git tag -a "v$VERSION" -F "${{ steps.generate-changelog.outputs.changelog_body_path }}" --cleanup=verbatim
|
||||
git push origin "v$VERSION"
|
||||
fi
|
||||
|
||||
- name: Create Gitea release
|
||||
env:
|
||||
RELEASE_PUBLISH_TOKEN: ${{ secrets.RELEASE_PUBLISH_TOKEN }}
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.value }}
|
||||
BODY_FILE="${{ steps.generate-changelog.outputs.changelog_body_path }}"
|
||||
|
||||
OWNER=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f1)
|
||||
REPO=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)
|
||||
|
||||
# Token-Auswahl
|
||||
TOKEN="${RELEASE_PUBLISH_TOKEN:-$ACTIONS_RUNTIME_TOKEN}"
|
||||
|
||||
if [[ -z "${RELEASE_PUBLISH_TOKEN:-}" ]]; then
|
||||
echo "::warning title=Limited Release Propagation::"
|
||||
echo "RELEASE_PUBLISH_TOKEN is not set. Using ACTIONS_RUNTIME_TOKEN instead."
|
||||
echo "⚠️ Release events may not trigger other workflows if created with the runtime token."
|
||||
echo
|
||||
fi
|
||||
|
||||
# Prüfe, ob der Release schon existiert
|
||||
if curl -sf "$GITHUB_API_URL/repos/$OWNER/$REPO/releases/tags/v$VERSION" \
|
||||
-H "Authorization: token $TOKEN" > /dev/null; then
|
||||
echo "🔁 Release for tag v$VERSION already exists, skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "🚀 Creating Gitea release for v$VERSION"
|
||||
|
||||
# Release-Beschreibung vorbereiten
|
||||
RELEASE_BODY=$(tail -n +2 "$BODY_FILE" | jq -Rs .)
|
||||
|
||||
curl -X POST "$GITHUB_API_URL/repos/$OWNER/$REPO/releases" \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @- <<EOF
|
||||
{
|
||||
"tag_name": "v$VERSION",
|
||||
"target_commitish": "main",
|
||||
"name": "Release v$VERSION",
|
||||
"body": $RELEASE_BODY,
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "✅ Release for tag $VERSION created successfully."
|
85
.github/workflows/CreateRelease.yml
vendored
85
.github/workflows/CreateRelease.yml
vendored
@@ -1,85 +0,0 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "VERSION"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pyinstaller openai
|
||||
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
shell: pwsh
|
||||
run: |
|
||||
$VERSION = (Get-Content -Path "./VERSION" -Raw).Trim()
|
||||
echo "VERSION=$VERSION" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8NoBOM -Append
|
||||
|
||||
- name: Run auto-py-to-exe
|
||||
run: |
|
||||
pyinstaller --noconfirm --onefile --console --name "ait-v${{ env.VERSION }}-winx64" --clean "./ait.py"
|
||||
|
||||
- name: Get previous release tag
|
||||
id: get_previous_release
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "Fetching previous release tag..."
|
||||
$previous_tag = git describe --tags --abbrev=0 HEAD^ 2>$null
|
||||
if (-not $previous_tag) {
|
||||
Write-Host "No previous tag found, using initial commit."
|
||||
$previous_tag = git rev-list --max-parents=0 HEAD
|
||||
}
|
||||
Write-Host "Previous tag: $previous_tag"
|
||||
echo "PREVIOUS_TAG=$previous_tag" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: Generate release notes
|
||||
id: generate_notes
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "Generating release notes from $env:PREVIOUS_TAG to HEAD..."
|
||||
$repo_url = git config --get remote.origin.url
|
||||
$notes = git log "$env:PREVIOUS_TAG..HEAD" --pretty=format:"- [`%h`]($repo_url/commit/%H): %s"
|
||||
Write-Host "Release notes:"
|
||||
Write-Host "$notes"
|
||||
"### Changes in this release" | Out-File -FilePath release_notes.md -Encoding utf8
|
||||
$notes | Out-File -FilePath release_notes.md -Encoding utf8 -Append
|
||||
|
||||
- name: Create Tag
|
||||
id: create_tag
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
git tag $env:VERSION
|
||||
git push origin $env:VERSION
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.VERSION }}
|
||||
name: Release ${{ env.VERSION }}
|
||||
body_path: release_notes.md
|
||||
files: |
|
||||
./dist/ait-v${{ env.VERSION }}-winx64.exe
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,3 +5,5 @@ ait.*.config.json
|
||||
dist/
|
||||
*.spec
|
||||
build/
|
||||
**/__pycache__
|
||||
.gitea/scripts/.env
|
||||
|
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.activeBackground": "#d48282",
|
||||
"activityBar.background": "#d48282",
|
||||
"activityBar.foreground": "#15202b",
|
||||
"activityBar.inactiveForeground": "#15202b99",
|
||||
"activityBarBadge.background": "#b8e7b8",
|
||||
"activityBarBadge.foreground": "#15202b"
|
||||
},
|
||||
"peacock.color": "#c75c5c"
|
||||
}
|
35
CHANGELOG.md
Normal file
35
CHANGELOG.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- *(workflows)* Add release sync to GitHub and clean up - ([8d5f168](https://git.0xmax42.io/maxp/ait/commit/8d5f168a10e674effe27aab69d348c52f3f8a58f))
|
||||
- *(workflows)* Add Gitea integration to sync action - ([81b2339](https://git.0xmax42.io/maxp/ait/commit/81b2339ea6d67a73dd62fb67b41db60388750610))
|
||||
- *(workflows)* Add GitHub release sync workflow - ([e478576](https://git.0xmax42.io/maxp/ait/commit/e4785769eac1dae3945a388dd745fa43555ea4da))
|
||||
- *(workflows)* Add GitHub release sync workflow - ([8b3117f](https://git.0xmax42.io/maxp/ait/commit/8b3117fdca5c9cd20cfb9ac3cfe0b0f1ee5f9656))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- *(workflows)* Correct token syntax in releases sync action - ([de05716](https://git.0xmax42.io/maxp/ait/commit/de05716b072f81351c603d82dafa17ee751b3dad))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(workflows)* Improve git-cliff installation and tagging - ([aa25ceb](https://git.0xmax42.io/maxp/ait/commit/aa25ceb957a07a5267bfd53dea8c58827c9c6840))
|
||||
- *(workflows)* Enable release event handling in sync-github - ([e875e78](https://git.0xmax42.io/maxp/ait/commit/e875e781a73349e6ac7092e3c599bdfb2526e08e))
|
||||
- *(workflows)* Remove unnecessary checkout step - ([45a6113](https://git.0xmax42.io/maxp/ait/commit/45a61134d6f8112c710fa1acdfb8c6205da287b4))
|
||||
|
||||
## [0.1.0] - 2025-05-24
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Add project structure and dependency management - ([a9ed247](https://git.0xmax42.io/maxp/ait/commit/a9ed247cb486cfc22779da9d6ab2db15f25dc1e6))
|
||||
- *(ci)* Add automated workflows for releases and nightly builds - ([579c70b](https://git.0xmax42.io/maxp/ait/commit/579c70b784d551426e841253a6d1de4cc53d65bd))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(vscode)* Customize activity bar and peacock colors - ([db8fda1](https://git.0xmax42.io/maxp/ait/commit/db8fda15df7b6a08dbd8eb4167e9b4862712392e))
|
||||
|
||||
|
12
README.md
12
README.md
@@ -1,3 +1,9 @@
|
||||

|
||||
|
||||
<p align="center">
|
||||
<img width="600" src="./docs/ait.webp">
|
||||
</p>
|
||||
|
||||
# AI-Generated Messages from Git Diffs and Logs
|
||||
|
||||
This script uses the OpenAI API to generate text based on the outputs of `git diff` and `git log` commands. It can be particularly useful for creating pull request descriptions, commit messages, or any other narrative that requires summarizing changes between different branches or commits in a Git repository.
|
||||
@@ -60,6 +66,12 @@ python ait.py --config custom
|
||||
|
||||
This command will look for a configuration file named `ait.custom.config`.
|
||||
|
||||
### Fallback Configuration File search
|
||||
|
||||
As a fallback, if no configuration file is found, the script will search for it in the user's home directory under `~\.ait\*`.
|
||||
|
||||
You can also provide a user wide configuration file by placing it in the `~\.ait\` directory.
|
||||
|
||||
### Command-Line Options
|
||||
|
||||
- `--config`: Path to a JSON config file or a keyword to identify a specific config (`ait.<KEYWORD>.config`). Default is `ait.config.json`.
|
||||
|
@@ -6,5 +6,5 @@
|
||||
"prompt": "Generate a concise commit message based on the provided Git diffs, including:\\n - A short and direct subject line (under 50 characters) summarizing the specific changes. No formatting should be used in the subject line.\\n - A brief bullet-point list of the exact modifications made, with basic Markdown formatting allowed in the body.\\n \\n Focus strictly on the changes themselves, avoiding any speculation about the reasons or potential impacts. Ensure that the message is informative enough to understand the changes without needing additional context.",
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1000,
|
||||
"temperature": 0.7
|
||||
"temperature": 0.6
|
||||
}
|
@@ -3,8 +3,8 @@
|
||||
"diff_expression": "main...",
|
||||
"log_expression": "main...",
|
||||
"system_prompt": "**You are an automatic pull request message generator and an expert in this field!**",
|
||||
"prompt": "Generate a concise pull request message based on the provided Git diffs, including:\\n - A short and direct subject line (under 50 characters) summarizing the specific changes. No formatting should be used in the subject line.\\n - A brief bullet-point list of the exact modifications made, with basic Markdown formatting allowed in the body.\\n - A detailed description in Markdown format explaining the changes, their purpose, and any additional context that is relevant for the reviewers.\\n \\n Focus strictly on the changes themselves, avoiding any speculation about the reasons or potential impacts beyond the modifications. Ensure that the message is informative enough to understand the changes and their context for a comprehensive review.",
|
||||
"prompt": "Generate a concise pull request message based on the provided Git diffs, including:\\n - A short and direct subject line (under 50 characters) summarizing the specific changes. No formatting should be used in the subject line.\\n - A brief bullet-point list of the exact modifications made, with basic Markdown formatting allowed in the body.\\n - A detailed description in Markdown format explaining the changes, and any additional context that is relevant for the reviewers.\\n \\n Focus strictly on the changes themselves, avoiding any speculation about the reasons or potential impacts.\\n **Do not include any closing statements or generic sentences. End the message immediately after providing the necessary details.**",
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1000,
|
||||
"temperature": 0.7
|
||||
"max_tokens": 2000,
|
||||
"temperature": 0.6
|
||||
}
|
104
cliff.toml
Normal file
104
cliff.toml
Normal file
@@ -0,0 +1,104 @@
|
||||
# CLIFF_VERSION=2.8.0
|
||||
# git-cliff ~ default configuration file
|
||||
# https://git-cliff.org/docs/configuration
|
||||
#
|
||||
# Lines starting with "#" are comments.
|
||||
# Configuration options are organized into tables and keys.
|
||||
# See documentation for more information on available options.
|
||||
[remote.gitea]
|
||||
owner = "maxp"
|
||||
repo = "ait"
|
||||
|
||||
[changelog]
|
||||
# postprocessors
|
||||
postprocessors = [
|
||||
{ pattern = '<GITEA_URL>', replace = "https://git.0xmax42.io" }, # replace gitea url
|
||||
]
|
||||
|
||||
# template for the changelog header
|
||||
header = """
|
||||
# Changelog\n
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://keats.github.io/tera/docs/#introduction
|
||||
body = """
|
||||
{%- macro remote_url() -%}
|
||||
<GITEA_URL>/{{ remote.gitea.owner }}/{{ remote.gitea.repo }}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% if version %}\
|
||||
{% if previous.version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}]\
|
||||
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% else %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% endif %}\
|
||||
{% else %}\
|
||||
## [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||
{{ commit.message | upper_first }} - \
|
||||
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# template for the changelog footer
|
||||
footer = """
|
||||
|
||||
"""
|
||||
# remove the leading and trailing s
|
||||
trim = true
|
||||
|
||||
# render body even when there are no releases to process
|
||||
# render_always = true
|
||||
# output file path
|
||||
# output = "test.md"
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = true
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# process each line of a commit as an individual commit
|
||||
split_commits = false
|
||||
# regex for preprocessing the commit messages
|
||||
commit_preprocessors = [
|
||||
# Replace issue numbers
|
||||
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
|
||||
# Check spelling of the commit with https://github.com/crate-ci/typos
|
||||
# If the spelling is incorrect, it will be automatically fixed.
|
||||
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
|
||||
]
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
|
||||
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
|
||||
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
|
||||
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
|
||||
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
|
||||
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
|
||||
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
|
||||
{ message = "^chore\\(changelog\\)", skip = true },
|
||||
{ message = "^chore\\(version\\)", skip = true },
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||
{ message = "^chore\\(pr\\)", skip = true },
|
||||
{ message = "^chore\\(pull\\)", skip = true },
|
||||
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
|
||||
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
|
||||
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
|
||||
{ message = ".*", group = "<!-- 10 -->💼 Other" },
|
||||
]
|
||||
# Regex to select git tags that represent releases.
|
||||
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = false
|
||||
# sort the tags topologically
|
||||
topo_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "newest"
|
BIN
docs/ait.webp
Normal file
BIN
docs/ait.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 306 KiB |
1133
poetry.lock
generated
Normal file
1133
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
pyproject.toml
Normal file
21
pyproject.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[tool.poetry]
|
||||
name = "ait"
|
||||
version = "0.1.0"
|
||||
description = "This script uses the OpenAI API to generate text based on the outputs of git diff and git log commands. It can be particularly useful for creating pull request descriptions, commit messages, or any other narrative that requires summarizing changes between different branches or commits in a Git repository."
|
||||
authors = ["Max P. <Mail@0xMax42.io>"]
|
||||
readme = "README.md"
|
||||
packages = [{ include = "ait", from = "src" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.12"
|
||||
openai = "^1.82.0"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
ait = "ait.__main__:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
twine = "^6.1.0"
|
0
src/ait/__init__.py
Normal file
0
src/ait/__init__.py
Normal file
4
src/ait/__main__.py
Normal file
4
src/ait/__main__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from ait.ait import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -22,7 +22,8 @@ def load_config(config_path):
|
||||
def resolve_config_path(config_input):
|
||||
"""
|
||||
Resolves the configuration file path. If a single word is provided,
|
||||
it looks for a file named 'ait.WORD.config' in the current directory.
|
||||
it looks for a file named 'ait.WORD.config.json' in the current directory first,
|
||||
then in a '.ait' directory in the user's home directory.
|
||||
|
||||
Parameters:
|
||||
- config_input (str): The input provided via the command-line argument.
|
||||
@@ -30,9 +31,24 @@ def resolve_config_path(config_input):
|
||||
Returns:
|
||||
- str: The resolved path to the configuration file.
|
||||
"""
|
||||
# If it's a keyword, construct the potential filenames
|
||||
if not config_input.endswith(".json"):
|
||||
config_input = f"ait.{config_input}.config.json"
|
||||
return config_input
|
||||
config_filename = f"ait.{config_input}.config.json"
|
||||
else:
|
||||
config_filename = config_input
|
||||
|
||||
# Check in the current directory
|
||||
if os.path.exists(config_filename):
|
||||
return config_filename
|
||||
|
||||
# Check in the user's home directory under .ait/
|
||||
home_directory = os.path.expanduser("~")
|
||||
user_config_path = os.path.join(home_directory, ".ait", config_filename)
|
||||
if os.path.exists(user_config_path):
|
||||
return user_config_path
|
||||
|
||||
# If nothing found, return the filename (it will fail later if non-existent)
|
||||
return config_filename
|
||||
|
||||
def run_git_commands(diff_expression, log_expression):
|
||||
"""
|
||||
@@ -48,7 +64,7 @@ def run_git_commands(diff_expression, log_expression):
|
||||
diff_command = ["git", "diff", diff_expression]
|
||||
diff_result = subprocess.run(diff_command, capture_output=True, text=True)
|
||||
|
||||
log_command = ["git", "log", log_expression, "--pretty=format:%h %s%n%b%n---%n"]
|
||||
log_command = ["git", "log", log_expression, "--pretty=\"format:%h%n%ad%n%s%n%n%b%n---%n\""]
|
||||
log_result = subprocess.run(log_command, capture_output=True, text=True)
|
||||
|
||||
return diff_result.stdout, log_result.stdout
|
||||
@@ -90,11 +106,11 @@ def generate_text_from_git_data(diff_output, log_output, system_prompt, user_pro
|
||||
)
|
||||
|
||||
# Extract and return the generated text
|
||||
generated_text = response.choices[0].message.content.strip()
|
||||
generated_text = response.choices[0].message.content.strip() # type: ignore
|
||||
return generated_text
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Default configuration file path
|
||||
def main():
|
||||
# Default configuration file path
|
||||
default_config_path = "ait.config.json"
|
||||
|
||||
# Parse command-line arguments
|
||||
@@ -146,4 +162,5 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
# Output the generated text
|
||||
print(generated_text)
|
||||
print("\n" + generated_text + "\n")
|
||||
|
Reference in New Issue
Block a user