# Part 3: Creating Tasks

version 9.3.0

Learn about custom task types, create one, and add it to your plugin.

In this section, you’ll:

- Understand what a custom task type is.

- Create a `SlackTask` class that contains the logic for sending a message.

- Add the necessary dependency for the Slack API client.

- Register the custom task in your plugin’s `apply` method.

## Step 0: Before you Begin

1. You initialized your plugin in part 1.

2. You added an extension to your plugin in part 2.

## Step 1: About Custom Tasks

If your plugin introduces new functionality, you’ll typically define a custom task type. This allows you to encapsulate specific logic, like sending a Slack message, into a reusable and configurable Gradle task. We’ll then register this task in our plugin so users can execute it with a simple command.

## Step 2: Create a Custom Task Type

Let’s create the class that will contain our Slack messaging logic.

    Create a new file called `SlackTask.kt` in `src/main/kotlin/org/example/` and add the following code:

    Create a new file called `SlackTask.groovy` in `src/main/groovy/org/example/` and add the following code:

plugin/src/main/kotlin/org/example/SlackTask.kt

    package org.example

    import com.slack.api.Slack
    import com.slack.api.methods.request.chat.ChatPostMessageRequest

    import org.gradle.api.DefaultTask
    import org.gradle.api.provider.Property
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction
    import kotlin.text.isNotEmpty

    /**
     * A custom Gradle task that sends a test message to a Slack channel.
     *
     * This task is useful for verifying Slack integration during build configuration.
     * It uses the Slack Web API and requires a bot token and a target channel.
     */
    abstract class SlackTask : DefaultTask() {

        // The Slack bot token (usually starts with "xoxb-") used to authenticate the API request.
        @get:Input
        abstract val token: Property<String>

        // The Slack channel name or ID (e.g., "#builds" or "C12345678") where the message will be sent.
        @get:Input
        abstract val channel: Property<String>

        // The message content to be sent to the specified Slack channel.
        @get:Input
        abstract val message: Property<String>

        /**
         * Sends a message to Slack when the task is executed.
         * Useful for manual testing of Slack integration from the command line.
         */
        @TaskAction
        fun send() {
            // Initialize the Slack client and get the API methods interface
            val slack = Slack.getInstance()
            val methods = slack.methods(token.get())

            // Create a Slack message request
            val request = ChatPostMessageRequest.builder()
                .channel(channel.get())
                .text(message.get())
                .build()

            // Send the message via the Slack API and check for success
            val response = methods.chatPostMessage(request)
            if (response.isOk) {
                logger.lifecycle("Slack message sent successfully to channel ${channel.get()}")
            } else {
                // Fail the build if the Slack API response indicates an error
                logger.error("Failed to send Slack message: ${response.error}")
                throw RuntimeException("Slack message failed: ${response.error}")
            }
        }
    }

plugin/src/main/groovy/org/example/SlackTask.groovy

    package org.example

    import com.slack.api.Slack
    import com.slack.api.methods.request.chat.ChatPostMessageRequest

    import org.gradle.api.DefaultTask
    import org.gradle.api.provider.Property
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction

    /**
     * A custom Gradle task that sends a test message to a Slack channel.
     *
     * This task is useful for verifying Slack integration during build configuration.
     * It uses the Slack Web API and requires a bot token and a target channel.
     */
    abstract class SlackTask extends DefaultTask {

        // The Slack bot token (usually starts with "xoxb-") used to authenticate the API request.
        @Input
        abstract Property<String> getToken()

        // The Slack channel name or ID (e.g., "#builds" or "C12345678") where the message will be sent.
        @Input
        abstract Property<String> getChannel()

        // The message content to be sent to the specified Slack channel.
        @Input
        abstract Property<String> getMessage()

        /**
         * Sends a message to Slack when the task is executed.
         * Useful for manual testing of Slack integration from the command line.
         */
        @TaskAction
        void send() {
            // Initialize the Slack client and get the API methods interface
            def slack = Slack.getInstance()
            def methods = slack.methods(token.get())

            // Create a Slack message request
            def request = ChatPostMessageRequest.builder()
                    .channel(channel.get())
                    .text(message.get())
                    .build()

            // Send the message via the Slack API and check for success
            def response = methods.chatPostMessage(request)
            if (response.isOk) {
                logger.lifecycle("Slack message sent successfully to channel ${channel.get()}")
            } else {
                // Fail the build if the Slack API response indicates an error
                logger.error("Failed to send Slack message: ${response.error}")
                throw new RuntimeException("Slack message failed: ${response.error}")
            }
        }
    }

This custom task type does a few important things:

- It extends `DefaultTask`, which gives it all the basic functionality of a Gradle task.

- It uses annotations like `@Input` and `@TaskAction` to clearly define its inputs and its primary action.

- The `@TaskAction` method uses the Slack API client to post a message.

- It includes robust error handling: if the Slack API call fails, the task will fail the build with a clear error message.

## Step 3: Add the Slack API Dependency

Since our custom task uses the Slack API client, we need to add it as a dependency in our plugin’s `build.gradle(.kts)` file.

plugin/build.gradle.kts

    dependencies {
        // Use the Java Slack Client APIs
        implementation("com.slack.api:slack-api-client:1.45.3")
    }

plugin/build.gradle

    dependencies {
        // Use the Java Slack Client APIs
        implementation("com.slack.api:slack-api-client:1.45.3")
    }

## Step 4: Register it in the Plugin

Now that we’ve defined our custom `SlackTask` class, we need to register it in our plugin’s `apply` method. This makes it available for users to run with a command like `./gradlew sendTestSlackMessage`.

    Open your plugin implementation file, `SlackPlugin.kt` (in `src/main/kotlin/org/example/`), and modify it to look like this:

    Open your plugin implementation file, `SlackPlugin.groovy` (in `src/main/groovy/org/example/`), and modify it to look like this:

plugin/src/main/kotlin/org/example/SlackPlugin.kt

    import org.gradle.api.tasks.TaskProvider

    abstract class SlackPlugin : Plugin<Project> {
        override fun apply(project: Project) {
            // Create the 'slack' extension so users can configure token, channel, and message
            val extension = project.extensions.create("slack", SlackExtension::class.java)

            // Register a task named 'sendTestSlackMessage' of type SlackTask
            val taskProvider: TaskProvider<SlackTask> = project.tasks.register("sendTestSlackMessage", SlackTask::class.java)

            // Configure the task using values from the extension
            taskProvider.configure {
                it.group = "notification" // Logical task grouping for help output
                it.description = "Sends a test message to Slack using the configured token and channel."

                // Bind extension values to the task's input properties
                it.token.set(extension.token)
                it.channel.set(extension.channel)
                it.message.set(extension.message)
            }
        }
    }

plugin/src/main/groovy/org/example/SlackPlugin.groovy

    import org.gradle.api.tasks.TaskProvider

    abstract class SlackPlugin implements Plugin<Project> {
        @Override
        void apply(Project project) {
            // Create the 'slack' extension so users can configure token, channel, and message
            def extension = project.extensions.create('slack', SlackExtension)

            // Register a task named 'sendTestSlackMessage' of type SlackTask
            TaskProvider<SlackTask> taskProvider = project.tasks.register('sendTestSlackMessage', SlackTask)

            // Configure the task using values from the extension
            taskProvider.configure {
                // Logical task grouping for help output
                it.group = 'notification'
                // Sends a test message to Slack using the configured token and channel.
                it.description = 'Sends a test message to Slack using the configured token and channel.'

                // Bind extension values to the task's input properties
                it.token.set(extension.token)
                it.channel.set(extension.channel)
                it.message.set(extension.message)
            }
        }
    }

This code:

- Registers a new task named `sendTestSlackMessage` of our custom `SlackTask` type.

- Configures the task with a group and description for better help output.

- Binds the task’s properties (`token`, `channel`, `message`) to the corresponding properties in our plugin’s `SlackExtension`. This is how the user’s configuration is passed to the task.

Next Step: Write a Unit Test >>