This is an automated email from the ASF dual-hosted git repository.

vincbeck 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 f09fbf30aaf Add return value to Slack operators for XCom (#63397)
f09fbf30aaf is described below

commit f09fbf30aaf53e90fdf0ad3601b8e6a21de2fc2a
Author: yuseok89 <[email protected]>
AuthorDate: Fri Mar 13 00:30:21 2026 +0900

    Add return value to Slack operators for XCom (#63397)
---
 .../src/airflow/providers/slack/operators/slack.py | 14 +++++-
 .../slack/tests/unit/slack/operators/test_slack.py | 50 ++++++++++++++++++++++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/providers/slack/src/airflow/providers/slack/operators/slack.py 
b/providers/slack/src/airflow/providers/slack/operators/slack.py
index bcfa8c85c99..56b4c90a387 100644
--- a/providers/slack/src/airflow/providers/slack/operators/slack.py
+++ b/providers/slack/src/airflow/providers/slack/operators/slack.py
@@ -46,6 +46,8 @@ class SlackAPIOperator(BaseOperator):
     :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
+
+    :return: The Slack API response. Returned value is pushed to XCom for 
downstream tasks.
     """
 
     def __init__(
@@ -101,7 +103,8 @@ class SlackAPIOperator(BaseOperator):
             raise ValueError(msg)
         if not self.api_params:
             self.construct_api_call_params()
-        self.hook.call(self.method, json=self.api_params)
+        response = self.hook.call(self.method, json=self.api_params)
+        return response.data
 
 
 class SlackAPIPostOperator(SlackAPIOperator):
@@ -128,6 +131,9 @@ class SlackAPIPostOperator(SlackAPIOperator):
         See https://api.slack.com/docs/attachments
     :param thread_ts: Provide another message's ``ts`` value to make this 
message a reply in a
         thread. See https://api.slack.com/messaging#threading (templated)
+
+    :return: The Slack API response data (e.g. ``ts``, ``channel``, 
``message``).
+        Returned value is pushed to XCom for downstream tasks.
     """
 
     template_fields: Sequence[str] = ("username", "text", "attachments", 
"blocks", "channel", "thread_ts")
@@ -223,6 +229,9 @@ class SlackAPIFileOperator(SlackAPIOperator):
     :param method_version: The version of the method of Slack SDK Client to be 
used, either "v1" or "v2".
     :param thread_ts: Provide another message's ``ts`` value to upload the 
file as a reply in a
         thread. See https://api.slack.com/messaging#threading (templated)
+
+    :return: List of Slack API response data from ``files_upload_v2`` (one per 
channel).
+        Returned value is pushed to XCom for downstream tasks.
     """
 
     template_fields: Sequence[str] = (
@@ -279,7 +288,7 @@ class SlackAPIFileOperator(SlackAPIOperator):
             )
 
     def execute(self, context: Context):
-        self.hook.send_file_v1_to_v2(
+        responses = self.hook.send_file_v1_to_v2(
             channels=self.channels,
             # For historical reason SlackAPIFileOperator use filename as 
reference to file
             file=self.filename,
@@ -290,3 +299,4 @@ class SlackAPIFileOperator(SlackAPIOperator):
             snippet_type=self.snippet_type,
             thread_ts=self.thread_ts,
         )
+        return [r.data for r in responses]
diff --git a/providers/slack/tests/unit/slack/operators/test_slack.py 
b/providers/slack/tests/unit/slack/operators/test_slack.py
index 485f52a8d63..c2d178bf6c1 100644
--- a/providers/slack/tests/unit/slack/operators/test_slack.py
+++ b/providers/slack/tests/unit/slack/operators/test_slack.py
@@ -200,6 +200,24 @@ class TestSlackAPIPostOperator:
             },
         )
 
+    @mock.patch("airflow.providers.slack.operators.slack.SlackHook")
+    def test_execute_returns_api_response(self, mock_hook):
+        """Test that execute returns Slack API response data for XCom."""
+        mock_response = mock.MagicMock()
+        mock_response.data = {"ok": True, "ts": "1234567890.123456", 
"channel": "C1234567890"}
+        mock_hook.return_value.call.return_value = mock_response
+
+        op = SlackAPIPostOperator(
+            task_id="slack",
+            slack_conn_id=SLACK_API_TEST_CONNECTION_ID,
+            channel=self.test_channel,
+            text=self.test_text,
+        )
+        result = op.execute({})
+
+        assert result == {"ok": True, "ts": "1234567890.123456", "channel": 
"C1234567890"}
+        assert result["ts"] == "1234567890.123456"
+
 
 class TestSlackAPIFileOperator:
     def setup_method(self):
@@ -368,3 +386,35 @@ class TestSlackAPIFileOperator:
                 snippet_type=None,
                 thread_ts="1234567890.123456",
             )
+
+    def test_execute_returns_api_response(self):
+        """Test that execute returns Slack API response data for XCom."""
+        mock_response = [mock.MagicMock()]
+        mock_response[0].data = {
+            "ok": True,
+            "ts": "1234567890.123456",
+            "channel": "C1234567890",
+            "file": {"id": "F1234567890"},
+        }
+
+        op = SlackAPIFileOperator(
+            task_id="slack",
+            slack_conn_id=SLACK_API_TEST_CONNECTION_ID,
+            channels="#test-channel",
+            content="test-content",
+        )
+        with mock.patch(
+            
"airflow.providers.slack.operators.slack.SlackHook.send_file_v1_to_v2",
+            return_value=mock_response,
+        ):
+            result = op.execute({})
+
+        expected = {
+            "ok": True,
+            "ts": "1234567890.123456",
+            "channel": "C1234567890",
+            "file": {"id": "F1234567890"},
+        }
+        assert result == [expected]
+        assert result[0]["ts"] == "1234567890.123456"
+        assert result[0]["file"]["id"] == "F1234567890"

Reply via email to