diff --git a/Dockerfile b/Dockerfile index 2174512..bf8cdcf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,6 +27,7 @@ ENV USERNAME="" \ GOTIFY_URL="" \ GOTIFY_TOKEN="" \ DISCORD_WEBHOOK_URL="" \ + SLACK_WEBHOOK_URL="" \ FLASK_ENV=production # Exposer le port 5000 pour l'API et le port 80 pour le serveur web diff --git a/README.md b/README.md index 3875fe0..22c488f 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ services: - GOTIFY_URL=gotify_url # Required if gotify is used - GOTIFY_TOKEN= # Required if gotify is used - DISCORD_WEBHOOK_URL= # Required if discord is used + - SLACK_WEBHOOK_URL= # Required if Slack is used volumes: - /path/to/github-ntfy:/github-ntfy/ ports: @@ -60,6 +61,7 @@ services: - GOTIFY_URL=gotify_url # Required if gotify is used - GOTIFY_TOKEN= # Required if gotify is used - DISCORD_WEBHOOK_URL= # Required if discord is used + - SLACK_WEBHOOK_URL= # Required if Slack is used volumes: - /path/to/github-ntfy:/github-ntfy/ ports: @@ -83,6 +85,7 @@ services: - GOTIFY_URL=gotify_url # Required if gotify is used - GOTIFY_TOKEN= # Required if gotify is used - DISCORD_WEBHOOK_URL= # Required if discord is used + - SLACK_WEBHOOK_URL= # Required if Slack is used volumes: - /path/to/github-ntfy:/github-ntfy/ ports: diff --git a/ntfy.py b/ntfy.py index 3c2bdce..420049c 100644 --- a/ntfy.py +++ b/ntfy.py @@ -20,6 +20,11 @@ from send_discord import ( docker_send_to_discord, ) +from send_slack import ( + github_send_to_slack, + docker_send_to_slack, +) + # Configuring the logger logging.basicConfig( level=logging.INFO, @@ -39,7 +44,7 @@ discord_webhook_url = os.environ.get("DISCORD_WEBHOOK_URL") def create_dockerhub_token(username, password): - url = "https://hub.docker.com//v2/users/login" + url = "https://hub.docker.com/v2/users/login" headers = {"Content-Type": "application/json"} data = json.dumps({"username": username, "password": password}) @@ -177,7 +182,7 @@ def get_changelog(repo): return latest_release_list["body"] return "Changelog not available" -def notify_all_services(github_latest_release, docker_latest_release, auth, ntfy_url, gotify_url, gotify_token, discord_webhook_url): +def notify_all_services(github_latest_release, docker_latest_release, auth, ntfy_url, gotify_url, gotify_token, discord_webhook_url, slack_webhook_url): threads = [] if ntfy_url: @@ -198,6 +203,12 @@ def notify_all_services(github_latest_release, docker_latest_release, auth, ntfy if docker_latest_release: threads.append(threading.Thread(target=docker_send_to_discord, args=(docker_latest_release, discord_webhook_url))) + if slack_webhook_url: + if github_latest_release: + threads.append(threading.Thread(target=github_send_to_slack, args=(github_latest_release, slack_webhook_url))) + if docker_latest_release: + threads.append(threading.Thread(target=docker_send_to_slack, args=(docker_latest_release, slack_webhook_url))) + for thread in threads: thread.start() @@ -215,6 +226,7 @@ if __name__ == "__main__": gotify_token = os.environ.get("GOTIFY_TOKEN") discord_webhook_url = os.environ.get("DISCORD_WEBHOOK_URL") timeout = float(os.environ.get("GHNTFY_TIMEOUT")) + slack_webhook_url = os.environ.get("SLACK_WEBHOOK_URL") if auth and (ntfy_url or gotify_url or discord_webhook_url): while True: @@ -223,7 +235,7 @@ if __name__ == "__main__": docker_watched_repos_list = get_docker_watched_repos() docker_latest_release = get_latest_docker_releases(docker_watched_repos_list) - notify_all_services(github_latest_release, docker_latest_release, auth, ntfy_url, gotify_url, gotify_token, discord_webhook_url) + notify_all_services(github_latest_release, docker_latest_release, auth, ntfy_url, gotify_url, gotify_token, discord_webhook_url, slack_webhook_url) time.sleep(timeout) else: diff --git a/send_discord.py b/send_discord.py index 16e2465..35e882f 100644 --- a/send_discord.py +++ b/send_discord.py @@ -27,9 +27,9 @@ def github_send_to_discord(releases, webhook_url): logger.info(f"The version of {app_name} has not changed. No notification sent.") continue # Move on to the next application - message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ“ *Changelog*:\n\n```{changelog}```" if len(message) > 2000: - message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nFull changelog: {app_url}" + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ”— *Release Link*: {app_url}" # Updating the previous version for this application cursor.execute( "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", @@ -67,9 +67,7 @@ def docker_send_to_discord(releases, webhook_url): logger.info(f"The digest of {app_name} has not changed. No notification sent.") continue - message = f"New version for {app_name}\nDigest: {digest_number}\nPublished on: {release_date}\n{app_url}" - if len(message) > 2000: - message = f"New version for {app_name}\nDigest: {digest_number}\nPublished on: {release_date}\nFull details: {app_url}" + message = f"🐳 *Docker Image Updated!*\n\nšŸ” *New Digest*: `{digest_number}`\n\nšŸ“¦ *App*: {app_name}\n\nšŸ“¢*Published*: {release_date}\n\nšŸ”— *Link*: {app_url}" cursor.execute( "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?)", diff --git a/send_gotify.py b/send_gotify.py index 367b56d..6cf9a98 100644 --- a/send_gotify.py +++ b/send_gotify.py @@ -34,7 +34,7 @@ def github_send_to_gotify(releases, token, url): logger.info(f"The version of {app_name} has not changed. No notification sent.") continue # Move on to the next application - message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ“ *Changelog*:\n\n```{changelog}```\n\nšŸ”— *Release Url*:{app_url}" # Updating the previous version for this application cursor.execute( "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", @@ -77,7 +77,7 @@ def docker_send_to_gotify(releases, token, url): logger.info(f"The digest of {app_name} has not changed. No notification sent.") continue # Move on to the next application - message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\n{app_url}" + message = f"🐳 *Docker Image Updated!*\n\nšŸ” *New Digest*: `{digest_number}`\n\nšŸ“¦ *App*: {app_name}\n\nšŸ“¢ *Published*: {release_date}\n\nšŸ”— *Release Url*:{app_url}" # Updating the previous digest for this application cursor.execute( "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?, ?)", diff --git a/send_ntfy.py b/send_ntfy.py index 210d1d3..3e4395d 100644 --- a/send_ntfy.py +++ b/send_ntfy.py @@ -32,7 +32,7 @@ def github_send_to_ntfy(releases, auth, url): logger.info(f"The version of {app_name} has not changed. No notification sent.") continue # Move on to the next application - message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ“ *Changelog*:\n\n```{changelog}```\n\n šŸ”— *Release Url*: {app_url}" # Updating the previous version for this application cursor.execute( "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", @@ -75,7 +75,7 @@ def docker_send_to_ntfy(releases, auth, url): logger.info(f"The digest of {app_name} has not changed. No notification sent.") continue # Move on to the next application - message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\n{app_url}" + message = f"🐳 *Docker Image Updated!*\n\nšŸ” *New Digest*: `{digest_number}`\n\nšŸ“¦ *App*: {app_name}\n\nšŸ“¢*Published*: {release_date}\n\n šŸ”— *Release Url*: {app_url}" # Updating the previous digest for this application cursor.execute( "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?, ?)", @@ -85,10 +85,10 @@ def docker_send_to_ntfy(releases, auth, url): headers = { "Authorization": f"Basic {auth}", - "Title": f"New version for {app_name}", + "Title": f"šŸ†• New version for {app_name}", "Priority": "urgent", "Markdown": "yes", - "Actions": f"view, Update {app_name}, {app_url}, clear=true", + "Actions": f"View, Update {app_name}, {app_url}, clear=true", } response = requests.post(f"{url}", headers=headers, data=message) if response.status_code == 200: diff --git a/send_slack.py b/send_slack.py new file mode 100644 index 0000000..a064675 --- /dev/null +++ b/send_slack.py @@ -0,0 +1,131 @@ +import requests +import sqlite3 +import logging + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", +) +logger = logging.getLogger(__name__) + +def get_db_connection(): + return sqlite3.connect("/github-ntfy/ghntfy_versions.db", check_same_thread=False) + +def github_send_to_slack(releases, webhook_url): + conn = get_db_connection() + cursor = conn.cursor() + for release in releases: + app_name = release["repo"].split("/")[-1] + version_number = release["tag_name"] + app_url = release["html_url"] + changelog = release["changelog"] + release_date = release["published_at"].replace("T", " ").replace("Z", "") + + cursor.execute("SELECT version FROM versions WHERE repo=?", (app_name,)) + previous_version = cursor.fetchone() + if previous_version and previous_version[0] == version_number: + logger.info(f"The version of {app_name} has not changed. No notification sent.") + continue + + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ“ *Changelog*:\n\n```{changelog}```" + if len(message) > 2000: + message = f"šŸ“Œ *New version*: {version_number}\n\nšŸ“¦*For*: {app_name}\n\nšŸ“… *Published on*: {release_date}\n\nšŸ“ *Changelog*:\n\n `truncated..` use šŸ”— instead " + + cursor.execute( + "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", + (app_name, version_number, changelog), + ) + conn.commit() + + + message = { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": f"{message}" + }, + "accessory": { + "type": "button", + "text": { + "type": "plain_text", + "text": "šŸ”— Release Url" + }, + "url": f"{app_url}", + "action_id": "button-action" + } + }, + { + "type": "divider" + } + ] + } + headers = { + "Content-Type": "application/json" + } + response = requests.post(webhook_url, json=message, headers=headers) + if response.status_code == 200: + logger.info(f"Message sent to Slack for {app_name}") + else: + logger.error(f"Failed to send message to Slack. Status code: {response.status_code}") + logger.error(f"Response: {response.text}") + conn.close() + +def docker_send_to_slack(releases, webhook_url): + conn = get_db_connection() + cursor = conn.cursor() + for release in releases: + app_name = release["repo"].split("/")[-1] + digest_number = release["digest"] + app_url = release["html_url"] + release_date = release["published_at"].replace("T", " ").replace("Z", "") + + cursor.execute("SELECT digest FROM docker_versions WHERE repo=?", (app_name,)) + previous_digest = cursor.fetchone() + if previous_digest and previous_digest[0] == digest_number: + logger.info(f"The digest of {app_name} has not changed. No notification sent.") + continue + + message = f"🐳 *Docker Image Updated!*\n\nšŸ” *New Digest*: `{digest_number}`\n\nšŸ“¦ *App*: {app_name}\n\nšŸ“¢*Published*: {release_date}" + + cursor.execute( + "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?)", + (app_name, digest_number), + ) + conn.commit() + + message = { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": f"{message}" + }, + "accessory": { + "type": "button", + "text": { + "type": "plain_text", + "text": "šŸ”— Release Url" + }, + "url": f"{app_url}", + "action_id": "button-action" + } + }, + { + "type": "divider" + } + ] + } + headers = { + "Content-Type": "application/json" + } + response = requests.post(webhook_url, json=message, headers=headers) + if 200 <= response.status_code < 300: + logger.info(f"Message sent to Slack for {app_name}") + else: + logger.error(f"Failed to send message to Slack. Status code: {response.status_code}") + logger.error(f"Response: {response.text}") + conn.close() +