Part 3: Creating Tasks
Learn about custom task types, create one, and add it to your plugin.
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:
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}")
}
}
}
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.
dependencies {
// Use the Java Slack Client APIs
implementation("com.slack.api:slack-api-client:1.45.3")
}
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:
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)
}
}
}
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 customSlackTask
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’sSlackExtension
. This is how the user’s configuration is passed to the task.
Next Step: Write a Unit Test >>