From c758aea06ab69a36cffa80ea4f03f6c93d0a3a2e Mon Sep 17 00:00:00 2001 From: iamprecieee Date: Mon, 24 Feb 2025 08:26:07 +0100 Subject: [PATCH 1/4] chore(branch): preserve v1 with customization features as legacy branch This commit establishes the v1-legacy branch to maintain the customizable version of Commit Quality Monitor. This version includes: - Configurable commit types, examples, and training data - Dynamic analyzer settings through Telex This branch serves as a stable reference for teams requiring customization capabilities while we move forward with v2's simplified architecture in main. The main branch README will document both versions and their distinct features. --- README.md | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c53f2b6..9538682 100644 --- a/README.md +++ b/README.md @@ -46,33 +46,36 @@ Git Commit Quality Monitor analyzes commit messages in real-time, providing inst ``` project_root/ ├── src/ -│ ├── core/ # Core Analysis Engine -│ │ ├── analyzer.py # ML-based commit analysis logic -│ │ └── models.py # Data models and structure +│ ├── core/ # Core Analysis Engine +│ │ ├── analyzer/ # ML-based commit analysis logic +| | | ├── analyzer.py +| | | ├── format_analyzer.py +| | | └── quality_analyzer.py +│ │ └── models.py # Data models and structure │ │ -│ ├── config/ # Configuration Management -│ │ ├── data.py # Training data, patterns, and examples -│ │ ├── config.py # Environment settings management -│ │ ├── integration_config.py # Telex integration configuration -│ │ └── middleware.py # CORS and trusted host middleware +│ ├── config/ # Configuration Management +│ │ ├── data.py # Training data, patterns, and examples +│ │ ├── config.py # Environment settings management +│ │ ├── integration_config.py # Telex integration configuration +│ │ └── middleware.py # CORS and trusted host middleware │ │ -│ ├── routers/ # API Routing Layer -│ │ ├── github.py # GitHub webhook endpoint handling -│ │ ├── telex.py # Telex webhook and integration -│ │ └── router.py # Main router configuration +│ ├── routers/ # API Routing Layer +│ │ ├── github.py # GitHub webhook endpoint handling +│ │ ├── telex.py # Telex webhook and integration +│ │ └── router.py # Main router configuration │ │ -│ └── utils/ # Utility Functions -│ └── telex_utils.py # Telex communication helpers +│ └── utils/ # Utility Functions +│ └── telex_utils.py # Telex communication helpers │ -├── tests/ # Test Suite -│ ├── __init__.py # Test configuration -│ ├── test_github.py # GitHub integration tests -│ └── test_telex.py # Telex integration tests +├── tests/ # Test Suite +│ ├── __init__.py # Test configuration +│ ├── test_github.py # GitHub integration tests +│ └── test_telex.py # Telex integration tests │ -├── .env.example # Environment variable template -├── main.py # Application entry point -├── requirements.txt # Project dependencies -└── README.md # Project documentation +├── .env.example # Environment variable template +├── main.py # Application entry point +├── requirements.txt # Project dependencies +└── README.md # Project documentation ``` ### Core Analysis Engine From 95bcfb18f6bcc8e491daf10782baa21bd8d49ad0 Mon Sep 17 00:00:00 2001 From: iamprecieee Date: Mon, 24 Feb 2025 09:28:56 +0100 Subject: [PATCH 2/4] refactor(core)!: simplify commit analysis pipeline BREAKING CHANGE: Remove runtime customization of commit rules - Remove custom commit types, examples, and training data configuration - Simplify webhook flow to direct Github -> Analysis -> Telex (-> Slack) - Update integration config for pre-configured settings This change maintains core analysis capabilities without runtime configuration. Users requiring customization can still use v1 branch. --- README.md | 63 ++++++++++---------------- src/config/integration_config.py | 24 +--------- src/core/analyzer/analyzer.py | 32 +------------ src/routers/github.py | 67 +++++++++++++++++---------- src/routers/router.py | 2 +- src/routers/telex.py | 53 ++++++---------------- tests/__init__.py | 2 +- tests/test_github.py | 7 +-- tests/test_telex.py | 78 ++++++++++---------------------- 9 files changed, 112 insertions(+), 216 deletions(-) diff --git a/README.md b/README.md index 9538682..0b2bf81 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Git Commit Quality Monitor +# Git Commit Quality Monitor v2 A smart Telex integration that helps teams maintain high-quality git commit messages using ML-powered analysis and real-time feedback. @@ -6,10 +6,15 @@ A smart Telex integration that helps teams maintain high-quality git commit mess Git Commit Quality Monitor analyzes commit messages in real-time, providing instant feedback on commit quality and suggestions for improvement. It uses machine learning to understand commit patterns and provides customized suggestions based on conventional commit standards and the development team's preferences. +## Version Notes + +- **v2 (current)**: Simplified architecture with pre-configured analysis rules +- **v1-legacy**: Available in v1-legacy branch, supports configurable commit rules and dynamic analyzer settings + ### Key Features - ⚡️ Real-time feedback through Slack -- 🎯 Customizable commit rules/conventions +- 🎯 Pre-configured commit standards based on conventional commits - 🔄 GitHub webhook integration - 🎨 Telex integration support - 🤖 Smart ML-powered commit message analysis and suggestions @@ -80,7 +85,7 @@ project_root/ ### Core Analysis Engine -The system implements a multi-step process to evaluate the quality of commit messages: +The v2 system implements a multi-step process to evaluate the quality of commit messages: #### Direct Pattern Matching - Matches against predefined commit types @@ -146,7 +151,7 @@ semantic_patterns = { ### GitHub Webhook Endpoint ```http -POST /api/v1/webhook/github/{telex_channel_id} +POST /api/v2/webhook/github/{telex_channel_id}/ Content-Type: application/json { @@ -160,11 +165,11 @@ Content-Type: application/json ] } ``` -Receives GitHub push events and forwards to Telex. +Receives GitHub push events, analyzes commits, and forwards to Telex. ### Telex Integration Endpoint ```http -POST /api/v1/webhook/telex +POST /api/v2/webhook/telex/ Content-Type: application/json { @@ -178,7 +183,7 @@ Content-Type: application/json ] } ``` -Receives commit messages from Telex and sends analysis results to slack. +Receives commit messages from Telex and forwards to slack. ### Integration Config ``` @@ -186,39 +191,9 @@ GET /integration.json ``` Returns integration configuration for Telex. -### Customizing Commit Analysis - -You can customize the analyzer through Telex integration settings: - -#### Commit Types -```json -{ - "feat": ["add", "implement", "new"], - "fix": ["fix", "resolve", "patch"] -} -``` - -#### Example Commits -```json -{ - "feat": "feat(auth): implement OAuth2 with role-based access\n\nImplemented OAuth2 protocol with role-based control to enhance security and scalability.", - "fix": "fix(api): resolve data race in concurrent requests\n\nFixed a race condition by adding synchronization mechanisms to prevent concurrent data modifications." -} -``` - -#### Training Data -```json -{ - "feat": [ - "feat(auth): implement JWT authentication flow\n\nImplemented JWT-based authentication with token expiration handling to secure user sessions.", - "feat(ui): add dark mode toggle with system preference detection\n\nAdded dark mode toggle that automatically adjusts based on system settings for improved user experience.", - ], -} -``` - ## Development Guide -### Basic Setup +### Setting Up v2 1. Clone the repository: ```bash @@ -273,7 +248,7 @@ uvicorn main:app --reload #### Step 3: Configure Webhook 1. Fill in the following fields: - - Payload URL: `https://your-domain/api/v1/webhook/github/{telex_channel_id}` + - Payload URL: `https://your-domain/api/v2/webhook/github/{telex_channel_id}/` - Replace `your-domain` with your actual domain - Replace `{telex_channel_id}` with your Telex channel ID 2. Set Content Type: @@ -325,12 +300,20 @@ uvicorn main:app --reload - Click on "Manage App" beside the added integration - Click on "Settings" - Add the slack webhook in the `slack_url` field - - Clear defaults in `commit_types`, `example_commits`, and `training_data` fields; replace with custom values if necessary. #### Step 3: Save and Activate 1. Click "Save Settings" 2. Enable the integration on the Apps dashboard +### Using v1 (Legacy Version) + +For teams requiring customizable features: +1. Switch to v1-legacy branch: + ```bash + git checkout v1-legacy + ``` +2. Follow setup instructions in v1-legacy README + ### Testing Your Integration #### Step 1: Make a Test Commit diff --git a/src/config/integration_config.py b/src/config/integration_config.py index 9db14be..5692d5e 100644 --- a/src/config/integration_config.py +++ b/src/config/integration_config.py @@ -21,11 +21,10 @@ def generate_json_config(): "integration_type": "output", "key_features": [ "Smart commit message analysis with ML-powered suggestions", - "Customizable commit rules that fit any team's style", "Instant notifications when commits need attention", "Easy setup with pre-configured commit patterns" ], - "website": settings.app_logo_url, + "website": settings.app_url, "author": "iamprecieee", "settings": [ { @@ -34,27 +33,6 @@ def generate_json_config(): "required": True, "description": "Slack Webhook URL", "default": "https://slack.com" - }, - { - "label": "commit_types", - "type": "text", - "required": False, - "description": "Provide custom commit types mapped to keywords that indicate type of change. Format: {'type': ['keyword1', 'keyword2']}. Example: {'docs': ['document', 'readme']} means commits with 'document' or 'readme' suggest documentation changes.", - "default": "{'feat': ['add', 'implement', 'new', 'introduce'], 'fix': ['fix', 'resolve', 'patch', 'address']}" - }, - { - "label": "example_commits", - "type": "text", - "required": False, - "description": "Set example commits for each custom commit type to guide new devs. These appear in suggestions when similar commits need fixing. Format: {'type1': 'example message1', 'type2': 'example message 2'}.", - "default": "{'feat': 'feat(auth): implement OAuth2 with role-based access\n\nImplemented OAuth2 protocol with role-based control to enhance security and scalability.', 'fix': 'fix(api): resolve data race in concurrent requests\n\nFixed a race condition by adding synchronization mechanisms to prevent concurrent data modifications.'}" - }, - { - "label": "training_data", - "type": "text", - "required": False, - "description": "Add custom data to train the analyzer with commits that match preferred style. More examples = better suggestions. Format: {'type1': ['example1', 'example2'], 'type2': ['example3', 'example4']}. The analyzer learns from these to better match preferred conventions.", - "default": "{'feat': ['feat(auth): implement OAuth2 with role-based access\n\nImplemented OAuth2 protocol with role-based control to enhance security and scalability.','feat(search): implement elasticsearch integration\n\nIntegrated Elasticsearch to boost search performance and enhance result accuracy.']}" } ], "target_url": settings.target_url diff --git a/src/core/analyzer/analyzer.py b/src/core/analyzer/analyzer.py index e7e0919..baa8f1f 100644 --- a/src/core/analyzer/analyzer.py +++ b/src/core/analyzer/analyzer.py @@ -3,12 +3,10 @@ example_commits, commit_training_data ) -from fastapi import HTTPException, status from ..models import CommitIssue from .format_analyzer import FormatAnalyzer from .quality_analyzer import QualityAnalyzer from datetime import datetime -import ast class CommitAnalyzer: @@ -17,38 +15,12 @@ class CommitAnalyzer: machine learning, and semantic analysis to ensure commit quality and provide improvement suggestions. """ - def __init__(self, settings: list) -> None: - """Initializes the analyzer with custom settings and prepares the ML classifier.""" - self.settings = settings - self.slack_url = None # Retrieved from settings + def __init__(self) -> None: + """Initializes the analyzer with commit types, examples, and training data.""" self.commit_types = commit_types self.example_commits = example_commits.copy() self.commit_training_data = commit_training_data.copy() - try: - self._apply_data_settings() - except Exception as e: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Invalid settings data: {str(e)}", - ) - - def _apply_data_settings(self) -> None: - """ - Updates analyzer configuration with custom settings provided through Telex. - Custom settings can override default commit types, examples, and training data. - Provides slack webhook url. - """ - for setting in self.settings: - if setting["label"] == "commit_types": - self.commit_types.update(ast.literal_eval(setting["default"].replace("\n", "\\n"))) if setting["default"] else self.commit_types - if setting["label"] == "example_commits": - self.example_commits.update(ast.literal_eval(setting["default"].replace("\n", "\\n"))) if setting["default"] else self.example_commits - if setting["label"] == "training_data": - self.commit_training_data.update(ast.literal_eval(setting["default"].replace("\n", "\\n"))) if setting["default"] else self.commit_training_data - if setting["label"] == "slack_url": - self.slack_url = setting["default"] - def _check_content_format(self, message: str) -> list[CommitIssue]: format_analyzer = FormatAnalyzer(message, self.commit_types, self.example_commits) return format_analyzer.check_all() diff --git a/src/routers/github.py b/src/routers/github.py index 2922f6e..681b4da 100644 --- a/src/routers/github.py +++ b/src/routers/github.py @@ -1,34 +1,55 @@ from fastapi.routing import APIRouter from ..core.models import GitHubPayload, TelexWebhookPayload +from typing import Annotated +from ..core.analyzer.analyzer import CommitAnalyzer from ..config.config import settings from ..utils.telex_utils import send_payload from fastapi.responses import JSONResponse -from fastapi import status, HTTPException +from fastapi import status, HTTPException, Query import json router = APIRouter(prefix="/github") -@router.post("/{telex_channel_id}", status_code=status.HTTP_200_OK) -async def github_webhook(telex_channel_id: str, payload: GitHubPayload): - """Endpoint to receive GitHub webhook events and forward the commits to Telex.""" - telex_payload = TelexWebhookPayload( - event_name="pushed_commits", - message=str(payload.commits), - status="success", - username=payload.pusher["name"], - ).model_dump_json() - - telex_url = f"{settings.telex_webhook_url}/{telex_channel_id}" - - try: - response = await send_payload(telex_payload, telex_url) - response_data = json.loads(response.decode().strip()) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Telex payload sending failed: {str(e)}", - ) - - return JSONResponse(content={"data": response_data}) +@router.post("/{telex_channel_id}/", status_code=status.HTTP_200_OK) +async def github_webhook( + telex_channel_id: str, + payload: GitHubPayload, + is_test: Annotated[str | None, Query()] = None, +): + """ + Endpoint to receive GitHub webhook events, analyze commit messages and + send results to Telex if issues are found. + """ + analyzer = CommitAnalyzer() + commits = payload.commits + all_messages = [] # Accumulate messages for test mode + + for commit in commits: + violations = analyzer.analyze_commit(commit["message"]) + if violations: + output_message = analyzer.format_analysis(commit, violations) + if is_test.lower() == "true": + all_messages.append(output_message) + else: + telex_payload = TelexWebhookPayload( + event_name="pushed_commits", + message=output_message, + status="success", + username=payload.pusher["name"], + ).model_dump_json() + + telex_url = f"{settings.telex_webhook_url}/{telex_channel_id}" + + try: + await send_payload(telex_payload, telex_url) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Telex payload sending failed: {str(e)}", + ) + if is_test.lower() == "true": + return JSONResponse(content=all_messages, status_code=status.HTTP_200_OK) + + return JSONResponse(content={"status": "success"}) diff --git a/src/routers/router.py b/src/routers/router.py index 1aa9657..7677f5d 100644 --- a/src/routers/router.py +++ b/src/routers/router.py @@ -3,6 +3,6 @@ from .telex import router as telex_router -webhook_router = APIRouter(prefix="/api/v1/webhook") +webhook_router = APIRouter(prefix="/api/v2/webhook") webhook_router.include_router(github_router) webhook_router.include_router(telex_router) \ No newline at end of file diff --git a/src/routers/telex.py b/src/routers/telex.py index 90ecaae..731c308 100644 --- a/src/routers/telex.py +++ b/src/routers/telex.py @@ -18,51 +18,24 @@ async def telex_webhook( payload: TelexTargetPayload, is_test: Annotated[str | None, Query()] = None ): - """ - Handle incoming webhook from Telex. Analyzes commit messages and sends - results to Slack if issues are found. - """ - try: - commit_message = ast.literal_eval(payload.message.replace("\n", "\\n")) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Error evaluating telex payload string: {str(e)}", - ) + """Handle incoming webhook from Telex and send results to Slack if webhook is provided.""" + commit_message = payload.message + try: - analyzer = CommitAnalyzer(settings=payload.settings) - slack_url = analyzer.slack_url - - all_messages = [] # Accumulate messages for test mode - - for commit in commit_message: - violations = analyzer.analyze_commit(commit["message"]) - if violations: - output_message = {"text": analyzer.format_analysis(commit, violations)} - if is_test == "true": - all_messages.append(output_message["text"]) - else: - try: - await send_payload(json.dumps(output_message), slack_url) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Telex payload sending failed: {str(e)}", - ) + for setting in payload.settings: + slack_url = setting["default"] if setting["label"] == "slack_url" else None + + if is_test.lower() == "true": + return JSONResponse(content=commit_message, status_code=status.HTTP_200_OK) + else: + await send_payload(commit_message, slack_url) - if is_test == "true": - return JSONResponse( - content=all_messages, - status_code=status.HTTP_200_OK, - ) except Exception as e: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Error analyzing commits: {str(e)}", + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Slack payload sending failed: {str(e)}", ) - return JSONResponse(content={"status": "success"}, status_code=status.HTTP_200_OK) - @telex_json_router.get("/integration.json", status_code=status.HTTP_200_OK) async def get_integration_config() -> dict: @@ -75,4 +48,4 @@ async def get_integration_config() -> dict: detail=f"Error retrieving config data: {str(e)}", ) - return json_data \ No newline at end of file + return json_data diff --git a/tests/__init__.py b/tests/__init__.py index bd7f851..6465dac 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,4 +2,4 @@ from main import app -client = TestClient(app, base_url="http://test/api/v1") \ No newline at end of file +client = TestClient(app, base_url="http://test/api/v2") \ No newline at end of file diff --git a/tests/test_github.py b/tests/test_github.py index 9374157..fea4c54 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -4,7 +4,7 @@ def test_send_to_telex_success(): response = client.post( - "/webhook/github/{telex_channel_id}", # Replace with an existing channel ID to receive messages + "/webhook/github/{telex_channel_id}/?is_test=true", # Replace with an existing channel ID to receive messages json={ "pusher": {"name": "test"}, "commits": [ @@ -19,14 +19,11 @@ def test_send_to_telex_success(): }, ) assert response.status_code == 200 - response_data = json.loads(response.content.decode()) - assert response_data["data"]["status"] == "success" - assert response_data["data"]["status_code"] == 202 def test_send_to_telex_failure(): response = client.post( - "/webhook/github/{telex_channel_id}", json={"pusher": {"name": "test"}} + "/webhook/github/{telex_channel_id}/?is_test=true", json={"pusher": {"name": "test"}} ) assert response.status_code == 422 response_data = json.loads(response.content.decode()) diff --git a/tests/test_telex.py b/tests/test_telex.py index 98cc7b3..fc0ad9f 100644 --- a/tests/test_telex.py +++ b/tests/test_telex.py @@ -4,24 +4,29 @@ def test_send_from_telex_success(): response = client.post( - "/webhook/telex?is_test=true", + "/webhook/telex/?is_test=true", json={ - "message": '[{"id": "8ce4cf04f4rw6w8600675237350b14b4", "message": "fix(auth): fix race condition\n\n- Added atomic transaction context in user creation functionality.", "timestamp": "2025-02-18T10:17:54+01:00", "url": "https://github.com/8", "author": {"name": "test", "email": "test@gmail.com"}}]', + "message": """ + 📝 *Commit Details* + └─ Hash: `bf238b5e` + └─ Author: test (test@gmail.com) + └─ URL: + └─ Time: 7:10AM. Monday, February 17, 2025. + └─ Message: + • ```remove unnecessary comment``` + + 🔍 *Analysis Results* + 🔴 Commit message type unidentifiable + └─ Seperate the commit type from the rest of the subject using ':'. + 🔵 Commit message may be missing detailed context + └─ Consider splitting your commit message into a concise subject and a detailed body. + + 💡 Resources + └─ Conventional Commits: + └─ Commit Best Practices: + └─ Git Best Practices: + """, "settings": [ - { - "label": "commit_types", - "type": "text", - "description": "Custom commit types and keywords", - "required": False, - "default": "{'feat': ['add', 'implement', 'new', 'introduce'], 'fix': ['fix', 'resolve', 'patch', 'address']}", - }, - { - "label": "example_commits", - "type": "text", - "required": True, - "description": "Set example commits for each custom commit type to guide new devs. These appear in suggestions when similar commits need fixing. Format: {'type1': 'example message1', 'type2': 'example message 2'}.", - "default": "{'feat': 'feat(auth): implement OAuth2 with role-based access\n\nImplemented OAuth2 protocol with role-based control to enhance security and scalability.', 'fix': 'fix(api): resolve data race in concurrent requests\n\nFixed a race condition by adding synchronization mechanisms to prevent concurrent data modifications.'}" - }, { "label": "slack_url", "type": "text", @@ -31,44 +36,11 @@ def test_send_from_telex_success(): }, ) assert response.status_code == 200 + response_data = json.loads(response.content.decode()) + for word in ("Commit message type unidentifiable", "missing detailed context"): + assert word in response_data - -def test_send_from_telex_failure(): - response = client.post( - "/webhook/telex?is_test=true", - json={ - "message": '[{"id": "8ce4cf04f4rw6w8600675237350b14b4", "message": "fix(auth): child jbcskb\n\nFixed a race condcvghdczhjvjhzcvhjvzhjvhjvczjonization mechanisms ashbcds.", "timestamp": "2025-02-18T10:17:54+01:00", "url": "https://github.com/8", "author": {"name": "test", "email": "test@gmail.com"}},{"id": "8ce4cf04f4rw6w8600675237350182b4", "message": "hello: publish notes here", "timestamp": "2025-03-18T10:17:54+01:00", "url": "https://github.com/8", "author": {"name": "test", "email": "test@gmail.com"}}]', - "settings": [ - { - "label": "slack_url", - "type": "text", - "required": True, - "description": "Slack Webhook URL", - "default": "https://slack.com" - }, - { - "label": "commit_types", - "type": "text", - "description": "Custom commit types and keywords", - "required": False, - "default": "", - }, - { - "label": "Example Commits", - "type": "text", - "required": True, - "description": "Set example commits for each custom commit type to guide new devs. These appear in suggestions when similar commits need fixing. Format: {'type1': 'example message1', 'type2': 'example message 2'}.", - "default": "{'feat': 'feat(auth): implement OAuth2 with role-based access\n\nImplemented OAuth2 protocol with role-based control to enhance security and scalability.', 'fix': 'fix(api): resolve data race in concurrent requests\n\nFixed a race condition by adding synchronization mechanisms to prevent concurrent data modifications.'}" - } - ], - }, - ) - assert response.status_code == 200 - response_data = json.loads(response.content.decode()) - for word in ("Potential gibberish words", "too long"): - assert word in response_data[0] - for word in ("Invalid commit type", "missing detailed context"): - assert word in response_data[1] \ No newline at end of file + \ No newline at end of file From e729eca30427c448a181b1a6d5a4afb6d3622927 Mon Sep 17 00:00:00 2001 From: iamprecieee Date: Mon, 24 Feb 2025 09:45:00 +0100 Subject: [PATCH 3/4] fix(routers): fix attribute error on query parameters - remove `.lower()` method on `is_test` parameter This fixes the attribute error when the query parameter is not given or None --- src/routers/github.py | 4 ++-- src/routers/telex.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routers/github.py b/src/routers/github.py index 681b4da..eb27cc8 100644 --- a/src/routers/github.py +++ b/src/routers/github.py @@ -30,7 +30,7 @@ async def github_webhook( violations = analyzer.analyze_commit(commit["message"]) if violations: output_message = analyzer.format_analysis(commit, violations) - if is_test.lower() == "true": + if is_test == "true": all_messages.append(output_message) else: telex_payload = TelexWebhookPayload( @@ -49,7 +49,7 @@ async def github_webhook( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Telex payload sending failed: {str(e)}", ) - if is_test.lower() == "true": + if is_test == "true": return JSONResponse(content=all_messages, status_code=status.HTTP_200_OK) return JSONResponse(content={"status": "success"}) diff --git a/src/routers/telex.py b/src/routers/telex.py index 731c308..0c68ad1 100644 --- a/src/routers/telex.py +++ b/src/routers/telex.py @@ -25,7 +25,7 @@ async def telex_webhook( for setting in payload.settings: slack_url = setting["default"] if setting["label"] == "slack_url" else None - if is_test.lower() == "true": + if is_test == "true": return JSONResponse(content=commit_message, status_code=status.HTTP_200_OK) else: await send_payload(commit_message, slack_url) From 0524338785722b1cd0d27a2de10b99cba48a8fb6 Mon Sep 17 00:00:00 2001 From: iamprecieee Date: Mon, 24 Feb 2025 10:23:45 +0100 Subject: [PATCH 4/4] fix(router): fix slack payload format - dedent and serialize payload to a format acceptable by slack webhook This fixes the 'expected str, bytes or os.PathLike object, not NoneType' when sending to slack. --- src/routers/telex.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/routers/telex.py b/src/routers/telex.py index 0c68ad1..fa02d2c 100644 --- a/src/routers/telex.py +++ b/src/routers/telex.py @@ -1,13 +1,11 @@ from fastapi.routing import APIRouter from ..core.models import TelexTargetPayload -from ..core.analyzer.analyzer import CommitAnalyzer from ..config.integration_config import generate_json_config from fastapi.responses import JSONResponse from fastapi import status, HTTPException, Query from typing import Annotated -import ast from ..utils.telex_utils import send_payload -import json +import textwrap, json router = APIRouter(prefix="/telex") @@ -19,16 +17,17 @@ async def telex_webhook( payload: TelexTargetPayload, is_test: Annotated[str | None, Query()] = None ): """Handle incoming webhook from Telex and send results to Slack if webhook is provided.""" - commit_message = payload.message + dedented_message = textwrap.dedent(payload.message) + commit_message = {"text": dedented_message} try: for setting in payload.settings: slack_url = setting["default"] if setting["label"] == "slack_url" else None if is_test == "true": - return JSONResponse(content=commit_message, status_code=status.HTTP_200_OK) + return JSONResponse(content=commit_message["text"], status_code=status.HTTP_200_OK) else: - await send_payload(commit_message, slack_url) + await send_payload(json.dumps(commit_message), slack_url) except Exception as e: raise HTTPException(