From 19d8e50505c7e562c27adaa5d59a390c896e2519 Mon Sep 17 00:00:00 2001 From: grigo Date: Tue, 9 Jun 2026 15:31:31 +0300 Subject: [PATCH] Fixed Git integration --- .env.example | 4 +-- backend/app/api/routes/webhooks.py | 6 +++- backend/app/projects/service.py | 46 ++++++++++++++++++++---------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index 1048574..98d417b 100644 --- a/.env.example +++ b/.env.example @@ -30,8 +30,8 @@ GITEA_TOKEN=your_gitea_api_token GITEA_PUBLIC_URL=https://git.grigowashere.ru GITEA_WEBHOOK_SECRET=generate_a_random_secret -# Gitea webhook URL (configure in repo settings): -# http://127.0.0.1:8080/api/v1/webhooks/gitea +# Gitea webhook URL (configure in repo settings; use BACKEND_PORT from host): +# http://127.0.0.1:8202/api/v1/webhooks/gitea REPOS_DIR=/data/repos diff --git a/backend/app/api/routes/webhooks.py b/backend/app/api/routes/webhooks.py index 537ef09..85660bd 100644 --- a/backend/app/api/routes/webhooks.py +++ b/backend/app/api/routes/webhooks.py @@ -57,7 +57,11 @@ def _post_close_notice(results: list[dict[str, Any]], owner: str, repo: str) -> async def gitea_webhook(request: Request, db: Session = Depends(get_db)) -> dict[str, Any]: body = await request.body() settings = get_settings() - signature = request.headers.get("X-Gitea-Signature") + signature = ( + request.headers.get("X-Gitea-Signature") + or request.headers.get("X-Gogs-Signature") + or request.headers.get("X-Hub-Signature-256") + ) if not _verify_gitea_signature(body, signature, settings.gitea_webhook_secret): raise HTTPException(status_code=401, detail="Invalid webhook signature") diff --git a/backend/app/projects/service.py b/backend/app/projects/service.py index fc622d4..84ca480 100644 --- a/backend/app/projects/service.py +++ b/backend/app/projects/service.py @@ -278,25 +278,38 @@ class ProjectService: for item in linked_items: if item.gitea_issue_number == gitea_num: - self._close_work_item(item, taiga) - results.append( - { - "commit": sha, - "closed": f"gitea #{gitea_num}, taiga #{item.taiga_story_ref}", - } - ) + try: + self._close_work_item(item, taiga) + results.append( + { + "commit": sha, + "closed": f"gitea #{gitea_num}, taiga #{item.taiga_story_ref}", + } + ) + except Exception as exc: + results.append( + {"error": f"work item {item.id} (gitea #{gitea_num}): {exc}"} + ) for ref in taiga_story_refs: project_id = self._project_id_for_ref(owner, repo, ref, linked_items) if not project_id: continue story = taiga.get_by_ref(project_id, ref, kind="userstory") - if story: - taiga.close_userstory(story["id"], project_id) + if story and not story.get("is_closed"): + try: + taiga.close_userstory(story["id"], project_id) + results.append({"commit": sha, "closed": f"taiga #{ref}"}) + except Exception as exc: + results.append({"error": f"taiga #{ref}: {exc}"}) for item in linked_items: - if item.taiga_story_ref == ref: - self._close_work_item(item, taiga, close_gitea=bool(gitea)) - results.append({"commit": sha, "closed": f"taiga #{ref}"}) + if item.taiga_story_ref == ref and item.status != "closed": + try: + self._close_work_item(item, taiga, close_gitea=bool(gitea)) + except Exception as exc: + results.append( + {"error": f"work item {item.id} (taiga #{ref}): {exc}"} + ) for ref in taiga_task_refs: binding = self.db.scalar( @@ -313,9 +326,12 @@ class ProjectService: if not taiga_proj: continue task = taiga.get_by_ref(taiga_proj.taiga_id, ref, kind="task") - if task: - taiga.close_task(task["id"], taiga_proj.taiga_id) - results.append({"commit": sha, "closed": f"taiga task #{ref}"}) + if task and not task.get("is_closed"): + try: + taiga.close_task(task["id"], taiga_proj.taiga_id) + results.append({"commit": sha, "closed": f"taiga task #{ref}"}) + except Exception as exc: + results.append({"error": f"taiga task #{ref}: {exc}"}) self.db.commit() return results