// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.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.

[[part5_add_dataflow_action]]
= Part 5: Add a DataFlow Action

Learn how to use Gradle's modern Dataflow API to hook into the build lifecycle and add an action to your plugin.

****
**In this section, you'll:**

- Understand what a `FlowAction` is and how it improves on older APIs.
- Create a `SlackBuildFlowAction` class to send a build notification.
- Register the `FlowAction` in your plugin to automatically execute at the end of the build.
****

[[part5_begin]]
== Step 0: Before you Begin

1. You initialized your plugin in <<part1_gradle_init_plugin.adoc#part1_begin,part 1>>.
2. You added an extension to your plugin in <<part2_add_extension.adoc#part2_begin,part 2>>.
3. You created a custom task in <<part3_create_custom_task.adoc#part3_begin, part3>>.
4. You wrote a unit test in <<part4_unit_test.adoc#part4_begin,part 4>>.

[[dp_part5_step1]]
== Step 1: Understanding the Dataflow API

**Dataflow Actions** are Gradle's modern, recommended way to react to the build lifecycle and handle build-wide events.
They are superior to older methods like `BuildListener` because they are fully compatible with the **Configuration Cache**, leading to faster and more reliable builds.

A `FlowAction` is a declarative, isolated, and lazy unit of work that runs in response to specific events, such as the build finishing.

The key components of the Dataflow API are:

* **`FlowScope`**: A service that allows you to register `FlowAction`s to be triggered under certain conditions.
* **`FlowAction<T>`**: An interface you implement to define the actual logic that runs.
* **`FlowParameters`**: A container for all the inputs to the `FlowAction`.

[[dp_part5_step2]]
== Step 2: Creating a Dataflow Action

Let's create the `FlowAction` that will send a Slack message at the end of the build.

====
[.multi-language-text.lang-kotlin]
=====
Create a new file named `SlackBuildFlowAction.kt` in `plugin/src/main/kotlin/org/example/` and add the following code:
=====
[.multi-language-text.lang-groovy]
=====
Create a new file named `SlackBuildFlowAction.groovy` in `plugin/src/main/groovy/org/example/` and add the following code:
=====
====

====
include::sample[dir="snippets/tutorials/developing-plugins/plugin-tutorial/kotlin",files="plugin/src/main/kotlin/org/example/SlackBuildFlowAction.kt[]"]
include::sample[dir="snippets/tutorials/developing-plugins/plugin-tutorial/groovy",files="plugin/src/main/groovy/org/example/SlackBuildFlowAction.groovy[]"]
====

This code completes two of the three main components of our flow action:

1.  The `SlackBuildFlowAction` class is a `FlowAction` that uses the Slack API client to send a message.
2.  The `SlackBuildFlowAction.Params` interface defines the input parameters for the action, including the `token`, `channel`, and a `buildFailed` flag.

[[dp_part5_step3]]
== Step 3: Registering the Dataflow Action in the Plugin

Now, we'll register the flow action in our plugin's `apply()` method to connect it to the build lifecycle.

Update your `SlackPlugin` class to look like this:

====
include::sample[dir="snippets/tutorials/developing-plugins/plugin-tutorial/kotlin",files="plugin/src/main/kotlin/org/example/SlackPlugin.kt[tags=final]"]
include::sample[dir="snippets/tutorials/developing-plugins/plugin-tutorial/groovy",files="plugin/src/main/groovy/org/example/SlackPlugin.groovy[tags=final]"]
====

In this code, we ask Gradle to inject two services that are essential for the Dataflow API:

* `@Inject abstract fun getFlowScope(): FlowScope`: This is used to register our action with the `always` scope, which means it will run after every build, regardless of the outcome.
* `@Inject abstract fun getFlowProviders(): FlowProviders`: This service provides access to data about the build, such as whether it succeeded or failed, via the `buildWorkResult` provider.

By using these services, we can configure our `FlowAction` to run automatically at the end of the build, providing a robust and cache-compatible way to send build notifications.

[.text-right]
**Next Step:** <<part6_functional_test.adoc#part6_functional_test,Write a Functional Test>> >>
