How do you declare a task in Gradle that packages a set of files into a Zip archive, and what are the key properties you configure on it?
answer
- Zip extends AbstractArchiveTask -> CopySpec
- from/into/include/exclude
- archiveFileName or baseName+version+classifier
- destinationDirectory (DirectoryProperty)
- archiveFile = Provider<RegularFile>
basics
~10 sRegister a task of type Zip, tell it which files to include with from(...), and set archiveFileName plus destinationDirectory to control the output file name and folder.
solid answer
~30 sUse `tasks.register<Zip>("packageDist")` and configure it like a copy: `from("src/dist")` selects the inputs, `into(...)` sets the path inside the archive, and `archiveFileName.set("app.zip")` plus `destinationDirectory.set(layout.buildDirectory.dir("dist"))` control where the archive lands. The `Zip` type extends `AbstractArchiveTask`, which itself is a copy-style task, so all the `CopySpec` methods (`from`, `into`, `include`, `exclude`, `rename`) work. Instead of a literal name you can compose `archiveBaseName`, `archiveVersion`, `archiveClassifier`, and `archiveExtension`, and Gradle builds the final name for you. The output file is exposed as `archiveFile`, a `Provider<RegularFile>`, which you can wire into downstream tasks lazily.
code
kotlin · 7 linestasks.register<Zip>("packageDist") {
from("src/main/dist")
into("app")
archiveBaseName.set("myapp")
archiveVersion.set("1.0")
destinationDirectory.set(layout.buildDirectory.dir("dist"))
}go deeper
Know that Zip is a built-in type, you register it, use from(...) for inputs, and set the output name and folder.
Explain the AbstractArchiveTask/CopySpec inheritance, the difference between into() and destinationDirectory, and the archiveBaseName/version/classifier composition.
Discuss wiring archiveFile (Provider<RegularFile>) into downstream tasks lazily and how archive tasks participate in up-to-date checking via their inputs.
Frame archive tasks as part of a publishable distribution pipeline, reproducible-build concerns (preserveFileTimestamps/duplicatesStrategy), and standardizing packaging conventions across modules.
## What a Zip task is `Zip` is a built-in Gradle task type for producing a `.zip` archive. It lives in the same family as `Jar`, `War`, and `Tar` — all of them extend `AbstractArchiveTask`, which in turn extends `AbstractCopyTask`. That inheritance is the key insight: **an archive task is just a copy task whose destination happens to be a single archive file rather than a directory.** Everything you know about copying applies. ## Selecting inputs (CopySpec) Because it is a copy task it implements `CopySpec`, so you populate it with: - `from(...)` — source files/dirs (the inputs that go into the archive). - `into("...")` — the *path inside the archive* (not a filesystem path). - `include(...)` / `exclude(...)` — Ant-style patterns to filter. - `rename(...)`, `filesMatching(...)`, `eachFile { ... }` — per-file tweaks. ## Naming the output You control the archive file name in two ways: 1. Set it directly: `archiveFileName.set("app.zip")`. 2. Compose it from parts and let Gradle assemble `baseName-version-classifier.extension`: - `archiveBaseName`, `archiveVersion`, `archiveClassifier`, `archiveExtension`. All of these are lazy `Property` types, so you set them with `.set(...)` (Kotlin DSL) or assignment. ## Where it lands `destinationDirectory` is a `DirectoryProperty`. Default is `build/distributions`. The fully resolved output is `archiveFile`, a `Provider<RegularFile>` — wire that into other tasks instead of hardcoding a path. ## Example ```kotlin tasks.register<Zip>("packageDist") { from("src/main/dist") into("app") // folder inside the zip archiveBaseName.set("myapp") archiveVersion.set(project.version.toString()) destinationDirectory.set(layout.buildDirectory.dir("dist")) } ``` This yields `build/dist/myapp-<version>.zip`. Run it with `./gradlew packageDist`.
- What does into("app") do versus destinationDirectory?into("app") sets the path *inside* the archive (files land under app/ in the zip). destinationDirectory is the *filesystem* folder where the resulting .zip file is written.
- How would you get the produced archive file to feed into another task?Use the archiveFile property — a Provider<RegularFile>. Wire it lazily: anotherTask.inputs.file(zipTask.flatMap { it.archiveFile }) or pass zipTask.flatMap { it.archiveFile } directly to a from(...).
Think of a Zip task as a moving-box: from() is what you pack, into() is how you label the compartments inside, and archiveFileName is the label you write on the outside of the box.
saying these in an interview costs you the question
- Confusing into() (path inside the archive) with destinationDirectory (filesystem output folder).
- Setting both archiveFileName and the compositional parts and expecting both to apply — archiveFileName overrides composition.