skip to content

Archive & Exec Tasks: Zip, Tar, Exec

The Zip, Tar, and Exec task types and their configuration: archive names, destination directories, command lines, and working directories. Comes up whenever a build must produce a distribution or shell out to another tool.

on this pageshow

questions

5

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?

level: juniorimportance: must knowfreq 55%

answer

  1. Zip extends AbstractArchiveTask -> CopySpec
  2. from/into/include/exclude
  3. archiveFileName or baseName+version+classifier
  4. destinationDirectory (DirectoryProperty)
  5. archiveFile = Provider<RegularFile>

basics

~10 s

Register 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 s

Use `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 lines
kotlin
tasks.register<Zip>("packageDist") {
    from("src/main/dist")
    into("app")
    archiveBaseName.set("myapp")
    archiveVersion.set("1.0")
    destinationDirectory.set(layout.buildDirectory.dir("dist"))
}

go deeper

for a junior

Know that Zip is a built-in type, you register it, use from(...) for inputs, and set the output name and folder.

for a middle

Explain the AbstractArchiveTask/CopySpec inheritance, the difference between into() and destinationDirectory, and the archiveBaseName/version/classifier composition.

for a senior

Discuss wiring archiveFile (Provider<RegularFile>) into downstream tasks lazily and how archive tasks participate in up-to-date checking via their inputs.

for a principal

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.

context

open as a page

How do you declare an Exec task to run an external command, and what are commandLine, args, and workingDir used for?

level: middleimportance: must knowfreq 45%

basics

~10 s

Register a task of type Exec and set commandLine to the executable plus its arguments. workingDir sets the directory to run in; args lets you set arguments separately from the executable.

open as a page

How does the Tar task differ from the Zip task, and how do you produce a gzip-compressed tarball (.tar.gz)?

level: middleimportance: should knowfreq 35%

basics

~10 s

Tar is the same kind of archive task as Zip but produces a .tar. Set its compression property to Compression.GZIP and give it a .tar.gz extension to get a compressed tarball.

open as a page

Explain how archive file naming and the archiveFile output are exposed as lazy Provider/Property types, and why wiring archiveFile downstream is better than hardcoding a path.

level: seniorimportance: should knowfreq 28%

basics

~10 s

Archive name parts (archiveBaseName, version, etc.) are Property objects and the resulting file is archiveFile, a Provider<RegularFile>. Wiring that provider into other tasks keeps the dependency lazy and lets Gradle track it correctly.

open as a page

Why can running external processes break Gradle's configuration cache, and how do ExecOperations and an Exec task differ in this regard?

level: seniorimportance: should knowfreq 22%

basics

~20 s

Running a process at configuration time isn't cacheable, so the configuration cache rejects it. Do process work at execution time — inside an Exec task's action, or via the injected ExecOperations service in a custom task — not in the configuration phase.

open as a page