Skip to content

Commit

Permalink
Add missing examples into Slack Provider (#35495)
Browse files Browse the repository at this point in the history
* Add missing examples into Slack Provider

* Fix provider.yaml

* Fix tests examples
  • Loading branch information
Taragolis committed Nov 7, 2023
1 parent 653ff1c commit 3fbd9d6
Show file tree
Hide file tree
Showing 13 changed files with 238 additions and 37 deletions.
2 changes: 1 addition & 1 deletion airflow/providers/slack/hooks/slack_webhook.py
Expand Up @@ -231,7 +231,7 @@ def send(
:param unfurl_links: Option to indicate whether text url should unfurl.
:param unfurl_media: Option to indicate whether media url should unfurl.
:param headers: Request headers for this request.
:param attachments: A collection of attachments.
:param attachments: (legacy) A collection of attachments.
"""
body = {
"text": text,
Expand Down
2 changes: 1 addition & 1 deletion airflow/providers/slack/notifications/slack.py
Expand Up @@ -46,13 +46,13 @@ class SlackNotifier(BaseNotifier):
:param channel: The channel to send the message to. Optional
:param username: The username to send the message as. Optional
:param icon_url: The icon to use for the message. Optional
:param attachments: A list of attachments to send with the message. Optional
:param blocks: A list of blocks to send with the message. Optional
:param timeout: The maximum number of seconds the client will wait to connect
and receive a response from Slack. Optional
:param base_url: A string representing the Slack API base URL. Optional
:param proxy: Proxy to make the Slack API call. Optional
:param retry_handlers: List of handlers to customize retry logic in ``slack_sdk.WebClient``. Optional
:param attachments: (legacy) A list of attachments to send with the message. Optional
"""

template_fields = ("text", "channel", "username", "attachments", "blocks")
Expand Down
2 changes: 1 addition & 1 deletion airflow/providers/slack/notifications/slack_webhook.py
Expand Up @@ -51,7 +51,7 @@ class SlackWebhookNotifier(BaseNotifier):
:param timeout: The maximum number of seconds the client will wait to connect. Optional
and receive a response from Slack. Optional
:param proxy: Proxy to make the Slack Incoming Webhook call. Optional
:param attachments: A list of attachments to send with the message. Optional
:param attachments: (legacy) A list of attachments to send with the message. Optional
:param retry_handlers: List of handlers to customize retry logic in ``slack_sdk.WebhookClient``. Optional
"""

Expand Down
8 changes: 4 additions & 4 deletions airflow/providers/slack/operators/slack.py
Expand Up @@ -114,10 +114,10 @@ class SlackAPIPostOperator(SlackAPIOperator):
:param username: Username that airflow will be posting to Slack as. (templated)
:param text: message to send to slack. (templated)
:param icon_url: URL to icon used for this message
:param attachments: extra formatting details. (templated)
See https://api.slack.com/docs/attachments
:param blocks: extra block layouts. (templated)
:param blocks: A list of blocks to send with the message. (templated)
See https://api.slack.com/reference/block-kit/blocks
:param attachments: (legacy) A list of attachments to send with the message. (templated)
See https://api.slack.com/docs/attachments
"""

template_fields: Sequence[str] = ("username", "text", "attachments", "blocks", "channel")
Expand All @@ -135,8 +135,8 @@ def __init__(
icon_url: str = (
"https://raw.githubusercontent.com/apache/airflow/main/airflow/www/static/pin_100.png"
),
attachments: list | None = None,
blocks: list | None = None,
attachments: list | None = None,
**kwargs,
) -> None:
self.method = "chat.postMessage"
Expand Down
4 changes: 3 additions & 1 deletion airflow/providers/slack/provider.yaml
Expand Up @@ -64,11 +64,13 @@ integrations:
- integration-name: Slack API
external-doc-url: https://api.slack.com/
how-to-guide:
- /docs/apache-airflow-providers-slack/operators/slack_operator_howto_guide.rst
- /docs/apache-airflow-providers-slack/operators/slack_api.rst
logo: /integration-logos/slack/Slack.png
tags: [service]
- integration-name: Slack Incoming Webhook
external-doc-url: https://api.slack.com/messaging/webhooks
how-to-guide:
- /docs/apache-airflow-providers-slack/operators/slack_webhook.rst
logo: /integration-logos/slack/Slack.png
tags: [service]

Expand Down
75 changes: 75 additions & 0 deletions docs/apache-airflow-providers-slack/operators/slack_api.rst
@@ -0,0 +1,75 @@
.. 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.
Slack API Operators
===================

Introduction
------------

`Slack API <https://api.slack.com/>`__ operators can post text messages or send files to specified Slack channel(s).

SlackAPIPostOperator
--------------------

Use the :class:`~airflow.providers.slack.operators.slack.SlackAPIPostOperator` to post messages to a Slack channel.


Using the Operator
^^^^^^^^^^^^^^^^^^

You could send simple text message

.. exampleinclude:: /../../tests/system/providers/slack/example_slack.py
:language: python
:dedent: 4
:start-after: [START slack_api_post_operator_text_howto_guide]
:end-before: [END slack_api_post_operator_text_howto_guide]


Or you could use `Block Kit <https://api.slack.com/reference/block-kit>`_ for create app layouts

.. exampleinclude:: /../../tests/system/providers/slack/example_slack.py
:language: python
:dedent: 4
:start-after: [START slack_api_post_operator_blocks_howto_guide]
:end-before: [END slack_api_post_operator_blocks_howto_guide]


SlackAPIFileOperator
--------------------

Use the :class:`~airflow.providers.slack.operators.slack.SlackAPIFileOperator` to send files to a Slack channel(s).


Using the Operator
^^^^^^^^^^^^^^^^^^

You could send file attachment by specifying file path

.. exampleinclude:: /../../tests/system/providers/slack/example_slack.py
:language: python
:start-after: [START slack_api_file_operator_howto_guide]
:end-before: [END slack_api_file_operator_howto_guide]


Or by directly providing file contents

.. exampleinclude:: /../../tests/system/providers/slack/example_slack.py
:language: python
:start-after: [START slack_api_file_operator_content_howto_guide]
:end-before: [END slack_api_file_operator_content_howto_guide]
Expand Up @@ -15,24 +15,32 @@
specific language governing permissions and limitations
under the License.
How-to Guide for Slack Operators
Slack Incoming Webhook Operators
================================

Introduction
------------

Slack operators can send text messages (:class:`~airflow.providers.slack.operators.slack.SlackAPIPostOperator`)
or files (:class:`~airflow.providers.slack.operators.slack.SlackAPIFileOperator`) to specified Slack channels.
Provide ``slack_webhook_conn_id`` for the connection, and specify ``channel`` (name or ID).
SlackWebhookOperator
--------------------

Example Code for Sending Files
------------------------------
Use the :class:`~airflow.providers.slack.operators.slack_webhook.SlackWebhookOperator` to post messages
to predefined Slack channel through `Incoming Webhook <https://api.slack.com/messaging/webhooks>`__

The example below demonstrates how to send files to a Slack channel by both specifying file names as well as
directly providing file contents. Note that the ``slack_conn_id``, ``channel``, and ``initial_comment`` values
for the operators are specified as ``default_args`` of the DAG.
Using the Operator
^^^^^^^^^^^^^^^^^^

.. exampleinclude:: /../../tests/system/providers/slack/example_slack.py
You could send simple text message

.. exampleinclude:: /../../tests/system/providers/slack/example_slack_webhook.py
:language: python
:dedent: 4
:start-after: [START slack_webhook_operator_text_howto_guide]
:end-before: [END slack_webhook_operator_text_howto_guide]


Or you could use `Block Kit <https://api.slack.com/reference/block-kit>`_ for create app layouts

.. exampleinclude:: /../../tests/system/providers/slack/example_slack_webhook.py
:language: python
:start-after: [START slack_operator_howto_guide]
:end-before: [END slack_operator_howto_guide]
:dedent: 4
:start-after: [START slack_webhook_operator_blocks_howto_guide]
:end-before: [END slack_webhook_operator_blocks_howto_guide]
Expand Up @@ -20,8 +20,8 @@
SqlToSlackWebhookOperator
=========================

Use the :class:`~airflow.providers.slack.transfers.sql_to_slack_webhook.SqlToSlackWebhookOperator` to post messages
to predefined Slack channel through `Incoming Webhook <https://api.slack.com/messaging/webhooks>`__.
Use the :class:`~airflow.providers.slack.transfers.sql_to_slack_webhook.SqlToSlackWebhookOperator` to post query result
as message to predefined Slack channel through `Incoming Webhook <https://api.slack.com/messaging/webhooks>`__.

Using the Operator
^^^^^^^^^^^^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions docs/apache-airflow-providers-slack/redirects.txt
@@ -0,0 +1 @@
operators/slack_operator_howto_guide.rst operators/slack_api.rst
5 changes: 1 addition & 4 deletions tests/always/test_project_structure.py
Expand Up @@ -606,10 +606,7 @@ class TestSlackProviderProjectStructure(ExampleCoverageTest):
"airflow.providers.slack.transfers.base_sql_to_slack.BaseSqlToSlackOperator",
"airflow.providers.slack.operators.slack.SlackAPIOperator",
}
MISSING_EXAMPLES_FOR_CLASSES = {
"airflow.providers.slack.operators.slack.SlackAPIPostOperator",
"airflow.providers.slack.operators.slack_webhook.SlackWebhookOperator",
}
MISSING_EXAMPLES_FOR_CLASSES = set()
DEPRECATED_CLASSES = {
"airflow.providers.slack.notifications.slack_notifier.py.",
"airflow.providers.slack.transfers.sql_to_slack.SqlToSlackOperator",
Expand Down
59 changes: 51 additions & 8 deletions tests/system/providers/slack/example_slack.py
Expand Up @@ -20,35 +20,78 @@
from datetime import datetime

from airflow.models.dag import DAG
from airflow.providers.slack.operators.slack import SlackAPIFileOperator
from airflow.providers.slack.operators.slack import SlackAPIFileOperator, SlackAPIPostOperator

ENV_ID = os.environ.get("SYSTEM_TESTS_ENV_ID")
DAG_ID = "slack_example_dag"
DAG_ID = "slack_api_example_dag"
SLACK_API_CONN_ID = os.environ.get("SLACK_API_CONN_ID", "slack_conn_id")
SLACK_CHANNEL = os.environ.get("SLACK_CHANNEL", "#general")
IMAGE_URL = "https://raw.githubusercontent.com/apache/airflow/main/airflow/www/static/pin_100.png"

# [START slack_operator_howto_guide]
with DAG(
dag_id=DAG_ID,
schedule=None,
start_date=datetime(2021, 1, 1),
default_args={"slack_conn_id": "slack", "channel": "#general", "initial_comment": "Hello World!"},
default_args={"slack_conn_id": SLACK_API_CONN_ID, "initial_comment": "Hello World!"},
max_active_runs=1,
tags=["example"],
) as dag:
# Send file with filename and filetype
# [START slack_api_post_operator_text_howto_guide]
slack_operator_post_text = SlackAPIPostOperator(
task_id="slack_post_text",
channel=SLACK_CHANNEL,
text=(
"Apache Airflow™ is an open-source platform for developing, "
"scheduling, and monitoring batch-oriented workflows."
),
)
# [END slack_api_post_operator_text_howto_guide]

# [START slack_api_post_operator_blocks_howto_guide]
slack_operator_post_blocks = SlackAPIPostOperator(
task_id="slack_post_blocks",
channel=SLACK_CHANNEL,
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": (
"*<https://github.com/apache/airflow|Apache Airflow™>* "
"is an open-source platform for developing, scheduling, "
"and monitoring batch-oriented workflows."
),
},
"accessory": {"type": "image", "image_url": IMAGE_URL, "alt_text": "Pinwheel"},
}
],
text="Fallback message",
)
# [END slack_api_post_operator_blocks_howto_guide]

# [START slack_api_file_operator_howto_guide]
slack_operator_file = SlackAPIFileOperator(
task_id="slack_file_upload_1",
channels=SLACK_CHANNEL,
filename="/files/dags/test.txt",
filetype="txt",
)
# [END slack_api_file_operator_howto_guide]

# Send file content
# [START slack_api_file_operator_content_howto_guide]
slack_operator_file_content = SlackAPIFileOperator(
task_id="slack_file_upload_2",
channels=SLACK_CHANNEL,
content="file content in txt",
)
# [END slack_operator_howto_guide]
# [END slack_api_file_operator_content_howto_guide]

slack_operator_file >> slack_operator_file_content
(
slack_operator_post_text
>> slack_operator_post_blocks
>> slack_operator_file
>> slack_operator_file_content
)


from tests.system.utils import get_test_run # noqa: E402
Expand Down
75 changes: 75 additions & 0 deletions tests/system/providers/slack/example_slack_webhook.py
@@ -0,0 +1,75 @@
# 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

import os
from datetime import datetime

from airflow.models.dag import DAG
from airflow.providers.slack.operators.slack_webhook import SlackWebhookOperator

ENV_ID = os.environ.get("SYSTEM_TESTS_ENV_ID")
DAG_ID = "slack_webhook_example_dag"
SLACK_WEBHOOK_CONN_ID = os.environ.get("SLACK_WEBHOOK_CONN_ID", "slack_default")
IMAGE_URL = "https://raw.githubusercontent.com/apache/airflow/main/airflow/www/static/pin_100.png"

with DAG(
dag_id=DAG_ID,
schedule=None,
start_date=datetime(2021, 1, 1),
max_active_runs=1,
tags=["example"],
) as dag:
# [START slack_webhook_operator_text_howto_guide]
slack_webhook_operator_text = SlackWebhookOperator(
task_id="slack_webhook_send_text",
slack_webhook_conn_id=SLACK_WEBHOOK_CONN_ID,
message=(
"Apache Airflow™ is an open-source platform for developing, "
"scheduling, and monitoring batch-oriented workflows."
),
)
# [END slack_webhook_operator_text_howto_guide]

# [START slack_webhook_operator_blocks_howto_guide]
slack_webhook_operator_blocks = SlackWebhookOperator(
task_id="slack_webhook_send_blocks",
slack_webhook_conn_id=SLACK_WEBHOOK_CONN_ID,
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": (
"*<https://github.com/apache/airflow|Apache Airflow™>* "
"is an open-source platform for developing, scheduling, "
"and monitoring batch-oriented workflows."
),
},
"accessory": {"type": "image", "image_url": IMAGE_URL, "alt_text": "Pinwheel"},
}
],
message="Fallback message",
)
# [END slack_webhook_operator_blocks_howto_guide]

slack_webhook_operator_text >> slack_webhook_operator_blocks

from tests.system.utils import get_test_run # noqa: E402

# Needed to run the example DAG with pytest (see: tests/system/README.md#run_via_pytest)
test_run = get_test_run(dag)
Expand Up @@ -29,7 +29,7 @@
SQL_TABLE = os.environ.get("SQL_TABLE", "test_table")
SQL_CONN_ID = "presto_default"
ENV_ID = os.environ.get("SYSTEM_TESTS_ENV_ID")
DAG_ID = "example_sql_to_slack"
DAG_ID = "example_sql_to_slack_webhook"

with models.DAG(
dag_id=DAG_ID,
Expand Down

0 comments on commit 3fbd9d6

Please sign in to comment.