# Part 6: Writing Tasks

version 9.2.0-20250823012548+0000

Learn the basics of authoring Gradle tasks by creating a simple one in your Build script.

In this section, you will:

- Understand Tasks

- Create a custom Task for the Plugin

## Step 0. Before you Begin

1. You initialized your Java app in part 1.

2. You understand the Gradle Build Lifecycle from part 2.

3. You added a subproject and a separate Build in part3.

4. You viewed a Settings file in part 4.

5. You authored a Build script in part 5.

## Step 1. Understand Tasks

A Task is an executable piece of code that contains sequences of actions.

Actions are added to a Task via the `doFirst{}` and `doLast{}` closures.

A Task can depend on other tasks.

## Step 2. Register and Configure Tasks

Early on in the tutorial, we registered and configured `task1` in the `app` build script:

app/build.gradle.kts

    tasks.register("task1"){  (1)
        println("REGISTER TASK1: This is executed during the configuration phase")
    }

    tasks.named("task1"){  (2)
        println("NAMED TASK1: This is executed during the configuration phase")
        doFirst {
            println("NAMED TASK1 - doFirst: This is executed during the execution phase")
        }
        doLast {
            println("NAMED TASK1 - doLast: This is executed during the execution phase")
        }
    }

1 | You can use the register() method to create new tasks.
2 | You can use the named() method to configure existing tasks.

app/build.gradle

    tasks.register("task1") {  (1)
        println("REGISTER TASK1: This is executed during the configuration phase")
    }

    tasks.named("task1") {  (2)
        println("NAMED TASK1: This is executed during the configuration phase")
        doFirst {
            println("NAMED TASK1 - doFirst: This is executed during the execution phase")
        }
        doLast {
            println("NAMED TASK1 - doLast: This is executed during the execution phase")
        }
    }

1 | You can use the register() method to create new tasks.
2 | You can use the named() method to configure existing tasks.

## Step 3. Create a custom Task

To create a custom task, you must subclass `DefaultTask` in Groovy DSL or `DefaultTask` in Kotlin DSL.

Create a custom class called `LicenseTask` with the code below and add it to the bottom of the `gradle/license-plugin/plugin/src/main/kotlin/license/LicensePlugin.kt` or `gradle/license-plugin/plugin/src/main/groovy/license/LicensePlugin.groovy` file:

gradle/license-plugin/plugin/src/main/kotlin/license/LicensePlugin.kt

    import org.gradle.api.Project
    import org.gradle.api.Plugin
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction
    import java.io.File
    import java.io.InputStream
    import java.nio.charset.Charset

    class LicensePlugin: Plugin<Project> {
        // Don't change anything here
    }

    abstract class LicenseTask : DefaultTask() {
        @Input
        val licenseFilePath = project.layout.settingsDirectory.file("license.txt").asFile.path

        @TaskAction
        fun action() {
            // Read the license text
            val licenseText = File(licenseFilePath).readText()
            // Walk the directories looking for java files
            project.layout.settingsDirectory.asFile.walk().forEach {
                if (it.extension == "java") {
                    // Read the source code
                    var ins: InputStream = it.inputStream()
                    var content = ins.readBytes().toString(Charset.defaultCharset())
                    // Write the license and the source code to the file
                    it.writeText(licenseText + content)
                }
            }
        }
    }

gradle/license-plugin/plugin/src/main/groovy/license/LicensePlugin.groovy

    import org.gradle.api.Project
    import org.gradle.api.Plugin
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction

    class LicensePlugin implements Plugin<Project> {
        // Don't change anything here
    }

    abstract class LicenseTask extends DefaultTask {
        @Input
        def licenseFilePath = project.layout.settingsDirectory.file("license.txt").asFile.path

        @TaskAction
        void action() {
            // Read the license text
            def licenseText = new File(licenseFilePath).text
            // Walk the directories looking for java files
            project.layout.settingsDirectory.asFile.eachFileRecurse { file ->
                int lastIndexOf = file.getName().lastIndexOf('.')
                if ((lastIndexOf != -1) && (file.getName().substring(lastIndexOf)) == ".java") {// Read the source code
                    def content = file.getText()
                    //println(licenseText + '\n' + content)
                    // Write the license and the source code to the file
                    file.text = licenseText + '\n' + content
                }
            }
        }
    }

The `LicenseTask` class encapsulates the task action logic and declares any inputs and outputs the task expects.

The task action is annotated with `@TaskAction`. Inside, the logic first finds a file called "license.txt". This file contains text for an Apache license:

license.txt

    /*
    * Licensed under the Apache License
    */

The task then looks for files with the extension `.java` and adds a license header.

The task has a single input, the license file name, annotated with `@Input`.

Gradle uses the `@Input` annotation to determine if the task needs to run. If the task has not run before or if the input value has changed since the previous execution, then Gradle will execute the task.

While a custom class has been created, it is not yet added to the `LicensePlugin`. Running `LicenseTask` is not currently possible.

All you can do for now is make sure `./gradlew build` runs without failing:

    $ ./gradlew build

    SETTINGS FILE: This is executed during the initialization phase

    > Configure project :app
    BUILD SCRIPT: This is executed during the configuration phase

    BUILD SUCCESSFUL in 1s
    13 actionable tasks: 6 executed, 7 up-to-date

Next Step: Writing Plugins >>