Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 80 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-success?style=flat&logo=githubactions)
![Python](https://img.shields.io/badge/Python-3.10%2B-blue?style=flat&logo=python)
![Telegram](https://img.shields.io/badge/Telegram-Bot-blue?style=flat&logo=telegram)
![Discord](https://img.shields.io/badge/Discord-Webhook-5865F2?style=flat&logo=discord)
[![CodeQL](https://github.com/reagento/relator/actions/workflows/codeql.yml/badge.svg)](https://github.com/reagento/relator/actions/workflows/codeql.yml)

**Relator** (Latin _referre_ - "to report") - delivers beautifully formatted GitHub notifications to Telegram. Get instant alerts for issues and PRs with smart labeling and clean formatting, keeping your team informed in real-time.
**Relator** (Latin _referre_ - "to report") - delivers beautifully formatted GitHub notifications to Telegram and Discord. Get instant alerts for issues and PRs with smart labeling and clean formatting, keeping your team informed in real-time.

## ✨ Features

- **Multi-Platform**: Send notifications to Telegram, Discord, or both simultaneously
- **Instant Notifications**: Get real-time alerts for new events
- **Rich Formatting**: Clean HTML and MD formatting
- **Label Support**: Automatically converts GitHub labels to Telegram hashtags
- **Rich Formatting**: HTML for Telegram, rich embeds for Discord
- **Label Support**: Automatically converts GitHub labels to hashtags
- **Customizable**: Multiple configuration options for different needs
- **Reliable**: Built-in retry mechanism for Telegram API
- **Reliable**: Built-in retry mechanism with exponential backoff

## 🚀 Quick Start

### Basic Usage
### Telegram Notifications

```yaml
name: Event Notifier
Expand Down Expand Up @@ -45,6 +47,45 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
```

### Discord Notifications

```yaml
name: Event Notifier

on:
issues:
types: [opened, reopened]
pull_request_target:
types: [opened, reopened]

permissions:
issues: read
pull_request: read

jobs:
notify:
name: "Discord notification"
runs-on: ubuntu-latest
steps:
- name: Send Discord notification for new issue or pull request
uses: reagento/relator@v1.6.0
with:
discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
github-token: ${{ secrets.GITHUB_TOKEN }}
```

### Both Platforms Simultaneously

```yaml
- name: Send notification to Telegram and Discord
uses: reagento/relator@v1.6.0
with:
tg-bot-token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
tg-chat-id: ${{ vars.TELEGRAM_CHAT_ID }}
discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
github-token: ${{ secrets.GITHUB_TOKEN }}
```

> github-token it's not required for public projects and is unlikely to hit any [limits](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#primary-rate-limit-for-unauthenticated-users). However, github actions uses IP-based limits, and since github actions has a limited pool of addresses, these limits are considered public, and you'll hit them very quickly.

### Advanced Configuration
Expand All @@ -71,6 +112,8 @@ jobs:

## 🔧 Setup Instructions

### Telegram Setup

1. Create a Telegram Bot

- Message `@BotFather` on [Telegram](https://t.me/botfather)
Expand All @@ -90,8 +133,26 @@ jobs:
- `TELEGRAM_BOT_TOKEN`
- `TELEGRAM_CHAT_ID`

### Discord Setup

1. Create a Discord Webhook

- Go to your Discord server settings
- Navigate to **Integrations** → **Webhooks**
- Click **New Webhook**
- Customize the webhook name and select the target channel
- Copy the **Webhook URL**

2. Configure GitHub Secrets
Add these secrets in your repository settings:

- `DISCORD_WEBHOOK_URL`
- `DISCORD_THREAD_ID` (optional)

## 📋 Example Output

### Telegram

Your Telegram notifications will look like this:

Issue:
Expand Down Expand Up @@ -120,9 +181,22 @@ Pull requests:
sent via relator
```

### Discord

Discord notifications appear as rich embeds with:

- **Color-coded embeds**: Green for issues, purple for pull requests
- **User avatars**: GitHub profile picture displayed
- **Repository links**: Clickable links to repository and issue/PR
- **Organized fields**: Repository, issue/PR number, changes (for PRs), branch info (for PRs)
- **Markdown formatting**: Clean formatting with proper code blocks, bold, italic, and links
- **Labels as hashtags**: Same label format as Telegram

## 🤝 Acknowledgments

This action uses the excellent [sulguk](https://github.com/Tishka17/sulguk) library by `@Tishka17` for reliable Telegram message delivery
This action uses:
- [sulguk](https://github.com/Tishka17/sulguk) by `@Tishka17` for reliable Telegram message delivery
- [markdownify](https://github.com/matthewwithanm/python-markdownify) for HTML to Markdown conversion for Discord

## 🌟 Support

Expand Down
18 changes: 13 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
name: "reagento/relator"
description: "Send Telegram notifications for new GitHub issues or PRs"
description: "Send Telegram and Discord notifications for new GitHub issues or PRs"
author: "Sehat1137"

inputs:
tg-bot-token:
description: "Telegram Bot Token"
required: true
required: false
tg-chat-id:
description: "Telegram Chat ID"
required: true
required: false
tg-message-thread-id:
description: "Telegram Message Thread ID"
required: false
discord-webhook-url:
description: "Discord Webhook URL"
required: false
discord-thread-id:
description: "Discord thread ID to post in (optional)"
required: false
github-token:
description: "GitHub Token for API access"
required: false
Expand Down Expand Up @@ -51,18 +57,20 @@ runs:
run: |
pip install -r $GITHUB_ACTION_PATH/requirements.txt

- name: Send Telegram notification
- name: Send notifications
shell: bash
env:
TELEGRAM_BOT_TOKEN: ${{ inputs.tg-bot-token }}
TELEGRAM_CHAT_ID: ${{ inputs.tg-chat-id }}
TELEGRAM_MESSAGE_THREAD_ID: ${{ inputs.tg-message-thread-id }}
DISCORD_WEBHOOK_URL: ${{ inputs.discord-webhook-url }}
DISCORD_THREAD_ID: ${{ inputs.discord-thread-id }}
GITHUB_TOKEN: ${{ inputs.github-token }}
EVENT_URL: ${{ github.event.issue.url || github.event.pull_request.url }}
BASE_URL: ${{ inputs.base-url }}
ATTEMPT_COUNT: ${{ inputs.attempt-count }}
HTML_TEMPLATE: ${{ inputs.html-template }}
MD_TEMPLATE: ${{ inputs.md-template }}
TELEGRAM_MESSAGE_THREAD_ID: ${{ inputs.tg-message-thread-id }}
JOIN_INPUT_WITH_LIST: ${{ inputs.join-input-with-list }}
CUSTOM_LABELS: ${{ inputs.custom-labels }}
run: |
Expand Down
47 changes: 36 additions & 11 deletions notifier/__main__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import os
import re
import sys
import traceback

from notifier.application.interactors import SendIssue, SendPR
from notifier.application.interfaces import Notifier
from notifier.application.services import RenderService
from notifier.infrastructure.discord_gateway import DiscordGateway
from notifier.infrastructure.github_gateway import GithubGateway
from notifier.infrastructure.telegram_gateway import TelegramGateway

Expand All @@ -24,15 +27,6 @@ def get_interactor(url: str) -> type[SendIssue] | type[SendPR]:


if __name__ == "__main__":
html_template = os.environ.get("HTML_TEMPLATE", "").strip()

telegram_gateway = TelegramGateway(
chat_id=os.environ["TELEGRAM_CHAT_ID"],
bot_token=os.environ["TELEGRAM_BOT_TOKEN"],
attempt_count=int(os.environ["ATTEMPT_COUNT"]),
message_thread_id=os.environ.get("TELEGRAM_MESSAGE_THREAD_ID"),
)

event_url = os.environ["EVENT_URL"]

github_gateway = GithubGateway(
Expand All @@ -49,15 +43,46 @@ def get_interactor(url: str) -> type[SendIssue] | type[SendPR]:
join_input_with_list=os.environ.get("JOIN_INPUT_WITH_LIST") == "1",
)

notifiers: list[Notifier] = []

tg_bot_token = os.environ.get("TELEGRAM_BOT_TOKEN")
tg_chat_id = os.environ.get("TELEGRAM_CHAT_ID")
if tg_bot_token and tg_chat_id:
html_template = os.environ.get("HTML_TEMPLATE", "").strip()
telegram_gateway = TelegramGateway(
chat_id=tg_chat_id,
bot_token=tg_bot_token,
attempt_count=int(os.environ.get("ATTEMPT_COUNT", "2")),
message_thread_id=os.environ.get("TELEGRAM_MESSAGE_THREAD_ID"),
custom_template=html_template,
)
notifiers.append(telegram_gateway)

discord_webhook_url = os.environ.get("DISCORD_WEBHOOK_URL")
if discord_webhook_url:
discord_gateway = DiscordGateway(
webhook_url=discord_webhook_url,
attempt_count=int(os.environ.get("ATTEMPT_COUNT", "2")),
)
notifiers.append(discord_gateway)

if not notifiers:
print(
"Error: No notification platform configured. "
"Please provide either TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID or DISCORD_WEBHOOK_URL",
file=sys.stderr,
)
sys.exit(1)

interactor = get_interactor(event_url)(
template=html_template,
github=github_gateway,
telegram=telegram_gateway,
notifiers=notifiers,
render_service=render_service,
)

try:
interactor.handler()
except Exception as e:
traceback.print_exc(file=sys.stderr)
print(f"Error processing event: {e}", file=sys.stderr)
sys.exit(1)
Loading
Loading