Compare commits
7 Commits
ddbf26f1cf
...
vetka_moya
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eb352f2c2 | |||
| c5db3fefad | |||
| 1c46d8bfb4 | |||
| 6fca0d7e71 | |||
| fa90e3c8df | |||
| 6bc6786919 | |||
| ab37abc4d4 |
243
Readme.md
Normal file
243
Readme.md
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
1. Получение API токена в Gitea
|
||||||
|
Войдите в Gitea
|
||||||
|
|
||||||
|
Перейдите в Настройки пользователя → Приложения (Settings → Applications)
|
||||||
|
|
||||||
|
В разделе "Manage Access Tokens" нажмите "Generate Token"
|
||||||
|
|
||||||
|
Укажите имя: webhook-handler
|
||||||
|
|
||||||
|
Выберите права: read:repository (достаточно для чтения коммитов)
|
||||||
|
|
||||||
|
Нажмите "Generate Token" и скопируйте токен (он показывается только один раз)
|
||||||
|
|
||||||
|
2. Настройка Webhook в Gitea
|
||||||
|
Откройте репозиторий в Gitea
|
||||||
|
|
||||||
|
Перейдите в Настройки → Вебхуки (Settings → Webhooks)
|
||||||
|
|
||||||
|
Нажмите "Add Webhook" → выберите "Gitea"
|
||||||
|
|
||||||
|
Заполните форму:
|
||||||
|
|
||||||
|
Поле Значение
|
||||||
|
Target URL http://IP-вашего-сервера:5000/webhook (например, http://192.168.1.100:5000/webhook)
|
||||||
|
HTTP Method POST
|
||||||
|
POST Content Type application/json
|
||||||
|
Secret (опционально) можно оставить пустым
|
||||||
|
Trigger On Выберите "Push Events" и "Delete Events"
|
||||||
|
Branch filter Оставьте пустым (или укажите конкретные ветки)
|
||||||
|
Active ✅ Включено
|
||||||
|
Нажмите "Add Webhook"
|
||||||
|
|
||||||
|
3. . Подготовка сервера
|
||||||
|
Установите Python и зависимости:
|
||||||
|
|
||||||
|
bash
|
||||||
|
# Установка Python (если не установлен)
|
||||||
|
# Для Ubuntu/Debian:
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install python3 python3-pip
|
||||||
|
|
||||||
|
# Для Windows: скачайте с python.org
|
||||||
|
|
||||||
|
# Установка зависимостей
|
||||||
|
pip install flask requests
|
||||||
|
Скачайте и настройте приложение:
|
||||||
|
|
||||||
|
bash
|
||||||
|
# Создайте директорию
|
||||||
|
mkdir gitea-webhook
|
||||||
|
cd gitea-webhook
|
||||||
|
и скопируйте в нее файл app.py
|
||||||
|
|
||||||
|
#Настройте переменные окружения:
|
||||||
|
|
||||||
|
bash
|
||||||
|
# Установите переменные (для Linux/Mac)
|
||||||
|
export GITEA_URL=https://gitea.your-company.com
|
||||||
|
export GITEA_TOKEN=your_api_token_here
|
||||||
|
|
||||||
|
# Для Windows (cmd)
|
||||||
|
set GITEA_URL=https://gitea.your-company.com
|
||||||
|
set GITEA_TOKEN=your_api_token_here
|
||||||
|
|
||||||
|
# Для Windows (PowerShell)
|
||||||
|
$env:GITEA_URL="https://gitea.your-company.com"
|
||||||
|
$env:GITEA_TOKEN="your_api_token_here"
|
||||||
|
Запустите приложение:
|
||||||
|
|
||||||
|
bash
|
||||||
|
python app.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Инструкция по тестированию обнаружения новых и удаленных коммитов
|
||||||
|
Подготовка
|
||||||
|
bash
|
||||||
|
# 1. Создайте тестовый репозиторий или используйте существующий
|
||||||
|
mkdir test-webhook
|
||||||
|
cd test-webhook
|
||||||
|
|
||||||
|
# 2. Инициализируйте репозиторий
|
||||||
|
git init
|
||||||
|
|
||||||
|
# 3. Добавьте удаленный репозиторий (Gitea)
|
||||||
|
git remote add origin https://gitea.daes.prosyst.ru/YOUR_USER/test-webhook.git
|
||||||
|
|
||||||
|
# 4. Создайте первый коммит (базовый)
|
||||||
|
echo "Initial content" > README.md
|
||||||
|
git add README.md
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
git push -u origin main
|
||||||
|
Сценарий 1: Создание ветки с несколькими коммитами
|
||||||
|
bash
|
||||||
|
# 1. Создайте ветку feature
|
||||||
|
git checkout -b feature/TSK-100
|
||||||
|
|
||||||
|
# 2. Создайте 3 коммита с задачами
|
||||||
|
echo "Feature 1" > feature1.txt
|
||||||
|
git add feature1.txt
|
||||||
|
git commit -m "TSK-100: Add feature 1"
|
||||||
|
|
||||||
|
echo "Feature 2" > feature2.txt
|
||||||
|
git add feature2.txt
|
||||||
|
git commit -m "TSK-100: Add feature 2"
|
||||||
|
|
||||||
|
echo "Feature 3" > feature3.txt
|
||||||
|
git add feature3.txt
|
||||||
|
git commit -m "TSK-100: Add feature 3"
|
||||||
|
|
||||||
|
# 3. Push ветку
|
||||||
|
git push -u origin feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[PUSH] user/test-webhook:feature/TSK-100
|
||||||
|
[NEW] 3 commits:
|
||||||
|
+ abc123: TSK-100: Add feature 1
|
||||||
|
+ def456: TSK-100: Add feature 2
|
||||||
|
+ ghi789: TSK-100: Add feature 3
|
||||||
|
[SUMMARY] Found tasks: TSK-100
|
||||||
|
Сценарий 2: Rebase (переписывание истории)
|
||||||
|
Вариант A: Изменение сообщения коммита (reword)
|
||||||
|
bash
|
||||||
|
# 1. Сделайте rebase последних 3 коммитов
|
||||||
|
git rebase -i HEAD~3
|
||||||
|
|
||||||
|
# В редакторе появится:
|
||||||
|
# pick abc123 TSK-100: Add feature 1
|
||||||
|
# pick def456 TSK-100: Add feature 2
|
||||||
|
# pick ghi789 TSK-100: Add feature 3
|
||||||
|
|
||||||
|
# 2. Измените pick на reword для второго коммита:
|
||||||
|
# pick abc123 TSK-100: Add feature 1
|
||||||
|
# reword def456 TSK-100: Add feature 2
|
||||||
|
# pick ghi789 TSK-100: Add feature 3
|
||||||
|
|
||||||
|
# 3. В открывшемся редакторе измените сообщение на:
|
||||||
|
# "TSK-100: Update feature 2"
|
||||||
|
|
||||||
|
# 4. Сохраните и выйдите
|
||||||
|
|
||||||
|
# 5. Force push
|
||||||
|
git push --force origin feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[PUSH] user/test-webhook:feature/TSK-100
|
||||||
|
[NEW] 3 commits:
|
||||||
|
+ abc123: TSK-100: Add feature 1
|
||||||
|
+ def456: TSK-100: Update feature 2
|
||||||
|
+ ghi789: TSK-100: Add feature 3
|
||||||
|
|
||||||
|
[REMOVED] 1 commits:
|
||||||
|
- def456_old: TSK-100: Add feature 2
|
||||||
|
Вариант B: Объединение коммитов (squash)
|
||||||
|
bash
|
||||||
|
# 1. Начните rebase
|
||||||
|
git rebase -i HEAD~3
|
||||||
|
|
||||||
|
# 2. Измените на squash:
|
||||||
|
# pick abc123 TSK-100: Add feature 1
|
||||||
|
# squash def456 TSK-100: Add feature 2
|
||||||
|
# squash ghi789 TSK-100: Add feature 3
|
||||||
|
|
||||||
|
# 3. В редакторе объедините сообщения:
|
||||||
|
# TSK-100: Add all features
|
||||||
|
|
||||||
|
# 4. Сохраните и выйдите
|
||||||
|
|
||||||
|
# 5. Force push
|
||||||
|
git push --force origin feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[PUSH] user/test-webhook:feature/TSK-100
|
||||||
|
[NEW] 1 commits:
|
||||||
|
+ abc123_new: TSK-100: Add all features
|
||||||
|
|
||||||
|
[REMOVED] 2 commits:
|
||||||
|
- def456_old: TSK-100: Add feature 2
|
||||||
|
- ghi789_old: TSK-100: Add feature 3
|
||||||
|
Вариант C: Удаление коммита (drop)
|
||||||
|
bash
|
||||||
|
# 1. Начните rebase
|
||||||
|
git rebase -i HEAD~3
|
||||||
|
|
||||||
|
# 2. Удалите строку с коммитом:
|
||||||
|
# pick abc123 TSK-100: Add feature 1
|
||||||
|
# drop def456 TSK-100: Add feature 2
|
||||||
|
# pick ghi789 TSK-100: Add feature 3
|
||||||
|
|
||||||
|
# 3. Сохраните и выйдите
|
||||||
|
|
||||||
|
# 4. Force push
|
||||||
|
git push --force origin feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[PUSH] user/test-webhook:feature/TSK-100
|
||||||
|
[NEW] 2 commits:
|
||||||
|
+ abc123: TSK-100: Add feature 1
|
||||||
|
+ ghi789: TSK-100: Add feature 3
|
||||||
|
|
||||||
|
[REMOVED] 1 commits:
|
||||||
|
- def456: TSK-100: Add feature 2
|
||||||
|
Сценарий 3: Изменение последнего коммита (amend)
|
||||||
|
bash
|
||||||
|
# 1. Измените последний коммит
|
||||||
|
echo "Updated feature" > feature3.txt
|
||||||
|
git add feature3.txt
|
||||||
|
git commit --amend -m "TSK-100: Updated feature 3"
|
||||||
|
|
||||||
|
# 2. Force push
|
||||||
|
git push --force origin feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[PUSH] user/test-webhook:feature/TSK-100
|
||||||
|
[NEW] 1 commits:
|
||||||
|
+ ghi789_new: TSK-100: Updated feature 3
|
||||||
|
|
||||||
|
[REMOVED] 1 commits:
|
||||||
|
- ghi789_old: TSK-100: Add feature 3
|
||||||
|
Сценарий 4: Удаление ветки
|
||||||
|
bash
|
||||||
|
# 1. Удалите ветку локально и на сервере
|
||||||
|
git checkout main
|
||||||
|
git branch -d feature/TSK-100
|
||||||
|
git push origin --delete feature/TSK-100
|
||||||
|
Ожидаемый вывод в консоли:
|
||||||
|
|
||||||
|
text
|
||||||
|
======================================================================
|
||||||
|
[WEBHOOK] Event: delete
|
||||||
|
[BRANCH DELETED] refs/heads/feature/TSK-100
|
||||||
|
[TASKS IN DELETED BRANCH] TSK-100
|
||||||
|
|
||||||
149
app.py
Normal file
149
app.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
from flask import Flask, request, jsonify
|
||||||
|
|
||||||
|
# Настройка логирования
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(message)s', handlers=[logging.StreamHandler(sys.stdout)])
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# Конфигурация
|
||||||
|
GITEA_URL = os.getenv('GITEA_URL', 'https://gitea-copy.teamlead.online')
|
||||||
|
GITEA_TOKEN = os.getenv('GITEA_TOKEN', '68dbda863bb4c51cb3ef1f8c4e8a69f7221240f5')
|
||||||
|
|
||||||
|
# Поиск задач вида ABC-123
|
||||||
|
TASK_PATTERN = re.compile(r'([A-Z]+-\d+)', re.IGNORECASE)
|
||||||
|
|
||||||
|
def find_tasks(text):
|
||||||
|
"""Находит ключи задач в тексте"""
|
||||||
|
return set(TASK_PATTERN.findall(text or ''))
|
||||||
|
|
||||||
|
def get_compare(owner, repo, base, head):
|
||||||
|
"""Запрашивает сравнение двух коммитов через API"""
|
||||||
|
url = f"{GITEA_URL}/api/v1/repos/{owner}/{repo}/compare/{base}...{head}"
|
||||||
|
headers = {'Authorization': f'token {GITEA_TOKEN}'} if GITEA_TOKEN else {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.get(url, headers=headers)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
logger.info(f"[API] Found {data.get('total_commits', 0)} commits")
|
||||||
|
return data.get('commits', [])
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(f"[API] Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@app.route('/webhook', methods=['POST'])
|
||||||
|
def webhook():
|
||||||
|
event = request.headers.get('X-Gitea-Event')
|
||||||
|
logger.info(f"\n{'='*70}\n[WEBHOOK] Event: {event}")
|
||||||
|
|
||||||
|
if event not in ['push', 'delete']:
|
||||||
|
return jsonify({'status': 'ignored'}), 200
|
||||||
|
|
||||||
|
data = request.get_json()
|
||||||
|
if not data:
|
||||||
|
return jsonify({'error': 'No data'}), 400
|
||||||
|
|
||||||
|
ref = data.get('ref', '')
|
||||||
|
logger.info(f"[WEBHOOK] Ref: {ref}")
|
||||||
|
|
||||||
|
# Удаление ветки
|
||||||
|
if event == 'delete':
|
||||||
|
branch = ref.replace('refs/heads/', '')
|
||||||
|
logger.info(f"[BRANCH DELETED] {branch}")
|
||||||
|
tasks = find_tasks(branch)
|
||||||
|
if tasks:
|
||||||
|
logger.info(f" [TASKS IN DELETED BRANCH] {', '.join(tasks)}")
|
||||||
|
return jsonify({'status': 'deleted'}), 200
|
||||||
|
|
||||||
|
# Только ветки
|
||||||
|
if not ref.startswith('refs/heads/'):
|
||||||
|
return jsonify({'status': 'ignored'}), 200
|
||||||
|
|
||||||
|
branch = ref.replace('refs/heads/', '')
|
||||||
|
before, after = data.get('before'), data.get('after')
|
||||||
|
repo = data.get('repository', {})
|
||||||
|
owner = repo.get('owner', {}).get('username')
|
||||||
|
repo_name = repo.get('name')
|
||||||
|
|
||||||
|
logger.info(f"[PUSH] {owner}/{repo_name}:{branch}")
|
||||||
|
logger.info(f" before: {before[:8]}, after: {after[:8]}")
|
||||||
|
|
||||||
|
# Создание ветки
|
||||||
|
if before == '0'*40:
|
||||||
|
logger.info(f"[BRANCH CREATED] {branch}")
|
||||||
|
tasks = find_tasks(branch)
|
||||||
|
if tasks:
|
||||||
|
logger.info(f" [TASKS IN BRANCH] {', '.join(tasks)}")
|
||||||
|
process_commits(data.get('commits', []), branch)
|
||||||
|
return jsonify({'status': 'created'}), 200
|
||||||
|
|
||||||
|
# Удаление ветки (через push с after=000)
|
||||||
|
if after == '0'*40:
|
||||||
|
logger.info(f"[BRANCH DELETED] {branch}")
|
||||||
|
return jsonify({'status': 'deleted'}), 200
|
||||||
|
|
||||||
|
# Обычный push - ищем новые и удаленные коммиты
|
||||||
|
logger.info("-"*70)
|
||||||
|
|
||||||
|
# Новые коммиты
|
||||||
|
new_commits = get_compare(owner, repo_name, before, after)
|
||||||
|
if new_commits:
|
||||||
|
logger.info(f"[NEW] {len(new_commits)} commits:")
|
||||||
|
for c in new_commits[:10]:
|
||||||
|
sha = c.get('sha', '')[:8]
|
||||||
|
msg = c.get('commit', {}).get('message', '')[:50]
|
||||||
|
logger.info(f" + {sha}: {msg}")
|
||||||
|
|
||||||
|
# Удаленные коммиты
|
||||||
|
removed_commits = get_compare(owner, repo_name, after, before)
|
||||||
|
if removed_commits:
|
||||||
|
logger.info(f"[REMOVED] {len(removed_commits)} commits:")
|
||||||
|
for c in removed_commits[:10]:
|
||||||
|
sha = c.get('sha', '')[:8]
|
||||||
|
msg = c.get('commit', {}).get('message', '')[:50]
|
||||||
|
tasks = find_tasks(msg)
|
||||||
|
task_info = f" [TASKS: {', '.join(tasks)}]" if tasks else ""
|
||||||
|
logger.info(f" - {sha}: {msg}{task_info}")
|
||||||
|
|
||||||
|
return jsonify({'status': 'ok'}), 200
|
||||||
|
|
||||||
|
def process_commits(commits, branch):
|
||||||
|
"""Обрабатывает коммиты и ищет задачи"""
|
||||||
|
if not commits:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(f"\n[COMMITS] {len(commits)} commits:")
|
||||||
|
all_tasks = find_tasks(branch)
|
||||||
|
|
||||||
|
for i, c in enumerate(commits, 1):
|
||||||
|
sha = c.get('id', '')[:8]
|
||||||
|
msg = c.get('message', '')
|
||||||
|
tasks = find_tasks(msg)
|
||||||
|
all_tasks.update(tasks)
|
||||||
|
logger.info(f" {i}. {sha}: {msg[:60]}" + (f" [TASKS: {', '.join(tasks)}]" if tasks else ""))
|
||||||
|
|
||||||
|
if all_tasks:
|
||||||
|
logger.info(f"\n[SUMMARY] Found tasks: {', '.join(sorted(all_tasks))}")
|
||||||
|
|
||||||
|
@app.route('/', methods=['GET'])
|
||||||
|
def index():
|
||||||
|
return f"""
|
||||||
|
<h1>Gitea Webhook Handler</h1>
|
||||||
|
<p>Webhook URL: <code>/webhook</code></p>
|
||||||
|
<p>Gitea API: <code>{GITEA_URL}</code></p>
|
||||||
|
<p>Token: {'[SET]' if GITEA_TOKEN else '[NOT SET]'}</p>
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
logger.info(f"\n{'='*70}\nGITEA WEBHOOK HANDLER\n{'='*70}")
|
||||||
|
logger.info(f"Server: http://0.0.0.0:5000")
|
||||||
|
logger.info(f"Webhook: https://gitea-copy.teamlead.online:5000/webhook")
|
||||||
|
logger.info(f"Gitea API: {GITEA_URL}")
|
||||||
|
logger.info(f"{'='*70}\n")
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=False)
|
||||||
6
com1.txt
6
com1.txt
@@ -1,4 +1,8 @@
|
|||||||
my 1
|
my 1
|
||||||
tooo
|
tooo
|
||||||
fhfhfhfh
|
fhfhfhfh
|
||||||
fbcdvfbdf 87987897u9879
|
nxgnbnx
|
||||||
|
gbngfnxfn
|
||||||
|
gfbnfxgnbh
|
||||||
|
fghgf
|
||||||
|
cbcvb dfgbdfgdfg
|
||||||
|
|||||||
2
com2.txt
2
com2.txt
@@ -1,3 +1,5 @@
|
|||||||
my 2
|
my 2
|
||||||
vbcvbcvbcvbcv
|
vbcvbcvbcvbcv
|
||||||
sdfhgfhfghdf
|
sdfhgfhfghdf
|
||||||
|
cghjhjdj dj djd dj
|
||||||
|
bb xb xb
|
||||||
|
|||||||
2
start_webhook.sh
Normal file
2
start_webhook.sh
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#! /usr/bin/bash
|
||||||
|
GITEA_URL=https://gitea.daes.prosyst.ru GITEA_TOKEN=your_api_token_here python app.py
|
||||||
Reference in New Issue
Block a user