This is an automated email from the ASF dual-hosted git repository.
eladkal pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new bdfebad5c9 Add `DiscordNotifier` (#31273)
bdfebad5c9 is described below
commit bdfebad5c9491234a78453856bd8c3baac98f75e
Author: Guilherme Cardoso de Vargas
<[email protected]>
AuthorDate: Fri Jun 16 02:49:03 2023 -0300
Add `DiscordNotifier` (#31273)
* Add DiscordNotifier
---------
Co-authored-by: guilherme.vargas <[email protected]>
Co-authored-by: Pankaj Koti <[email protected]>
Co-authored-by: Shivam Shrey <[email protected]>
Co-authored-by: eladkal <[email protected]>
---
.../providers/discord/notifications/__init__.py | 17 +++++
airflow/providers/discord/notifications/discord.py | 82 ++++++++++++++++++++++
airflow/providers/discord/provider.yaml | 3 +
tests/providers/discord/notifications/__init__.py | 16 +++++
.../discord/notifications/test_discord.py | 58 +++++++++++++++
5 files changed, 176 insertions(+)
diff --git a/airflow/providers/discord/notifications/__init__.py
b/airflow/providers/discord/notifications/__init__.py
new file mode 100644
index 0000000000..217e5db960
--- /dev/null
+++ b/airflow/providers/discord/notifications/__init__.py
@@ -0,0 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/airflow/providers/discord/notifications/discord.py
b/airflow/providers/discord/notifications/discord.py
new file mode 100644
index 0000000000..629b8c2b59
--- /dev/null
+++ b/airflow/providers/discord/notifications/discord.py
@@ -0,0 +1,82 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from functools import cached_property
+
+from airflow.exceptions import AirflowOptionalProviderFeatureException
+
+try:
+ from airflow.notifications.basenotifier import BaseNotifier
+except ImportError:
+ raise AirflowOptionalProviderFeatureException(
+ "Failed to import BaseNotifier. This feature is only available in
Airflow versions >= 2.6.0"
+ )
+
+from airflow.providers.discord.hooks.discord_webhook import DiscordWebhookHook
+
+ICON_URL: str =
"https://raw.githubusercontent.com/apache/airflow/main/airflow/www/static/pin_100.png"
+
+
+class DiscordNotifier(BaseNotifier):
+ """
+ Discord BaseNotifier.
+
+ :param discord_conn_id: Http connection ID with host as
"https://discord.com/api/" and
+ default webhook endpoint in the extra field in the
form of
+ {"webhook_endpoint":
"webhooks/{webhook.id}/{webhook.token}"}
+ :param text: The content of the message
+ :param username: The username to send the message as. Optional
+ :param avatar_url: The URL of the avatar to use for the message. Optional
+ :param tts: Text to speech.
+ """
+
+ # A property that specifies the attributes that can be templated.
+ template_fields = ("discord_conn_id", "text", "username", "avatar_url",
"tts")
+
+ def __init__(
+ self,
+ discord_conn_id: str = "discord_webhook_default",
+ text: str = "This is a default message",
+ username: str = "Airflow",
+ avatar_url: str = ICON_URL,
+ tts: bool = False,
+ ):
+ super().__init__()
+ self.discord_conn_id = discord_conn_id
+ self.text = text
+ self.username = username
+ self.avatar_url = avatar_url
+
+ # If you're having problems with tts not being recognized in
__init__(),
+ # you can define that after instantiating the class
+ self.tts = tts
+
+ @cached_property
+ def hook(self) -> DiscordWebhookHook:
+ """Discord Webhook Hook."""
+ return DiscordWebhookHook(http_conn_id=self.discord_conn_id)
+
+ def notify(self, context):
+ """Send a message to a Discord channel."""
+ self.hook.username = self.username
+ self.hook.message = self.text
+ self.hook.avatar_url = self.avatar_url
+ self.hook.tts = self.tts
+
+ self.hook.execute()
diff --git a/airflow/providers/discord/provider.yaml
b/airflow/providers/discord/provider.yaml
index ee751779bc..6dedfc1fe0 100644
--- a/airflow/providers/discord/provider.yaml
+++ b/airflow/providers/discord/provider.yaml
@@ -58,3 +58,6 @@ hooks:
connection-types:
- hook-class-name:
airflow.providers.discord.hooks.discord_webhook.DiscordWebhookHook
connection-type: discord
+
+notifications:
+ - airflow.providers.discord.notifications.discord.DiscordNotifier
diff --git a/tests/providers/discord/notifications/__init__.py
b/tests/providers/discord/notifications/__init__.py
new file mode 100644
index 0000000000..13a83393a9
--- /dev/null
+++ b/tests/providers/discord/notifications/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/tests/providers/discord/notifications/test_discord.py
b/tests/providers/discord/notifications/test_discord.py
new file mode 100644
index 0000000000..279dafa515
--- /dev/null
+++ b/tests/providers/discord/notifications/test_discord.py
@@ -0,0 +1,58 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from airflow.models import Connection
+from airflow.providers.discord.notifications.discord import DiscordNotifier
+from airflow.utils import db
+
+
[email protected](autouse=True)
+def setup():
+ db.merge_conn(
+ Connection(
+ conn_id="my_discord_conn_id",
+ conn_type="discord",
+ host="https://discordapp.com/api/",
+ extra='{"webhook_endpoint":
"webhooks/00000/some-discord-token_000"}',
+ )
+ )
+
+
+@patch("airflow.providers.discord.notifications.discord.DiscordWebhookHook.execute")
+def test_discord_notifier_notify(mock_execute):
+ notifier = DiscordNotifier(
+ discord_conn_id="my_discord_conn_id",
+ text="This is a test message",
+ username="test_user",
+ avatar_url="https://example.com/avatar.png",
+ tts=False,
+ )
+ context = MagicMock()
+
+ notifier.notify(context)
+
+ mock_execute.assert_called_once()
+ assert notifier.hook.username == "test_user"
+ assert notifier.hook.message == "This is a test message"
+ assert notifier.hook.avatar_url == "https://example.com/avatar.png"
+ assert notifier.hook.tts is False