File and Directory Configuring Ways

tasks.register<Copy>("apiDocs") {
    from("docs/api.adoc")
    into(layout.buildDirectory.dir("build/docs"))
}
tasks.register<Copy>("apiDocs") {
    from(project.file("docs/api.adoc"))
    into(layout.buildDirectory.dir("build/docs"))
}
tasks.register<Copy>("apiDocs") {
    from(layout.projectDirectory.dir("docs"))
    into(layout.buildDirectory.dir("docs"))
}
tasks.register<Copy>("apiDocs") {
    from(fileTree(layout.projectDirectory) {
        include("docs/*.adoc")
    })
    into(layout.buildDirectory)
}

// or 

tasks.register<Copy>("apiDocs") {
    from(layout.projectDirectory)
    include("docs/*.adoc")
    into(layout.buildDirectory)
}

Relative Path

When you use Gradle file APIs, Gradle handles making sure they work relative to the project your build script code is related to

That means if you’re in the build script of multi-project build, any files you reference are relative to that subproject’s directory

tasks.register<Copy>("apiDocsHtml") {
    from(layout.projectDirectory.file("/src/main/resources/static/api.html"))
    into(layout.buildDirectory)
}

When you run task, Gradle copies the file, using the subproject directory as root of the relative path

This means that you should always use the file APIs and never create a file object directly

If you were to do that, the file would be created relative to the current working directory, which Gradle makes no guarantees about