github: fix discord webhook payload truncation for long commit messages
Fix Discord webhook failures caused by overly long commit body content
that exceeds Discord embed size limits, preventing notification delivery.
Problem Analysis:
Discord webhooks were failing with HTTP 400 errors when commit messages
contained extensive body content. The error response {"embeds": ["0"]}
indicated the first embed was invalid, typically due to field length
violations. Discord enforces strict limits on embed field sizes:
- Title: 256 characters maximum
- Description: 4096 characters maximum
- Field values: 1024 characters maximum
Large commits with detailed implementation notes, problem analysis, and
technical documentation were exceeding these limits, causing webhook
delivery failures and missed commit notifications.
Implementation Changes:
1. Text Truncation Function:
- Added truncate_text() with intelligent content preservation
- Attempts truncation at paragraph boundaries (double newlines)
- Falls back to sentence boundaries (periods with spaces)
- Uses ellipsis (...) to indicate truncated content
- Ensures truncation only when more than half content remains
2. Field Length Management:
- Title truncated to 256 character Discord limit
- Description conservatively limited to 2000 characters for safety
- Maintains existing field structure and formatting
- Preserves commit author and URL fields unchanged
3. Debug Information:
- Added payload size reporting in test mode
- Character count logging for title and description fields
- Enhanced troubleshooting capabilities for future issues
4. Backward Compatibility:
- No changes to function signatures or environment variables
- Existing webhook URLs and configuration remain unchanged
- Short commit messages pass through unmodified
- All existing functionality preserved
Technical Details:
- Truncation uses string slicing with boundary detection
- Conservative 2000 character limit provides buffer below Discord's 4096 limit
- Test mode provides detailed payload analysis for debugging
- JSON payload generation unchanged except for field content
Benefits:
- Reliable Discord notification delivery for all commit types
- Intelligent content preservation maintains readability
- Debug capabilities improve webhook troubleshooting
- Zero configuration changes required for existing setups
Testing:
- Verified fix resolves HTTP 400 errors for problematic commit e08c7ffc
- Confirmed short commit messages remain unaffected
- Tested intelligent truncation at paragraph and sentence boundaries
- Validated payload size reduction maintains Discord compatibility
This fix ensures consistent Discord webhook delivery while preserving
essential commit information through intelligent content truncation.
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s1859815462496f8ak
diff --git a/.github/scripts/discord_notify.py b/.github/scripts/discord_notify.py
index b73b5d2..2a794c5 100755
--- a/.github/scripts/discord_notify.py
+++ b/.github/scripts/discord_notify.py
@@ -46,6 +46,26 @@
print(f"Failed to get commit information: {e}")
sys.exit(1)
+def truncate_text(text, max_length):
+ """Truncate text to fit within Discord's limits."""
+ if len(text) <= max_length:
+ return text
+ # Find a good place to cut off, preferably at a sentence or paragraph boundary
+ truncated = text[:max_length - 3] # Leave room for "..."
+
+ # Try to cut at paragraph boundary
+ last_double_newline = truncated.rfind('\n\n')
+ if last_double_newline > max_length // 2: # Only if we're not cutting too much
+ return truncated[:last_double_newline] + "\n\n..."
+
+ # Try to cut at sentence boundary
+ last_period = truncated.rfind('. ')
+ if last_period > max_length // 2: # Only if we're not cutting too much
+ return truncated[:last_period + 1] + " ..."
+
+ # Otherwise just truncate with ellipsis
+ return truncated + "..."
+
def main():
# Validate we're running in the correct environment
validate_environment()
@@ -65,12 +85,17 @@
# Create timestamp
timestamp = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')[:-3] + 'Z'
+ # Truncate fields to fit Discord's limits
+ # Discord embed limits: title (256), description (4096), field value (1024)
+ title = truncate_text(commit_message, 256)
+ description = truncate_text(commit_body, 2000) # Use 2000 to be safe
+
# Create Discord webhook payload
payload = {
"embeds": [
{
- "title": commit_message,
- "description": commit_body,
+ "title": title,
+ "description": description,
"color": 5814783,
"fields": [
{
@@ -91,6 +116,12 @@
# Convert to JSON
json_payload = json.dumps(payload)
+
+ # Debug: print payload size info
+ if os.environ.get('DISCORD_TEST_MODE') == '1':
+ print(f"Payload size: {len(json_payload)} bytes")
+ print(f"Title length: {len(payload['embeds'][0]['title'])} chars")
+ print(f"Description length: {len(payload['embeds'][0]['description'])} chars")
# Test mode - just print the payload
if os.environ.get('DISCORD_TEST_MODE') == '1':