Checkpoint Lab — Gradle Installation, Wrapper, CLI, Settings, Build Scripts, and Project Bootstrap
Prove that a disposable JVM project can be built only through a verified Wrapper and isolated Gradle User Home, then break and repair one settings assumption while preserving evidence and cleanup boundaries.
Prove that a disposable JVM project can be built only through a verified Wrapper and isolated Gradle User Home, then break and repair one settings assumption while preserving evidence and cleanup boundaries.
Learning objectives
- Create and explain every source-controlled file in a disposable Gradle JVM project.
- Pin Gradle 9.7.1 and verify both Wrapper distribution and Wrapper-JAR identity.
- Run all normal project operations through the Wrapper with an isolated Gradle User Home.
- Record system-versus-wrapper identity without letting system Gradle become the build contract.
-
Predict and verify state changes in Wrapper distributions, Gradle
User Home, project
.gradle, andbuild/. - Break and repair a settings assumption, then prove complete cleanup.
1. Checkpoint acceptance contract
Your evidence bundle must answer six questions: What Gradle version does the repository select? What JVM runs it? What Java target does the application use? Which Wrapper bytes were trusted? Which files define the build? Which generated directories/caches appeared after execution?
The project is successful only if another engineer can read the evidence and distinguish source configuration from downloaded/cache/generated state.
2. Setup and preflight
# POSIX — from a neutral parent directory, not an untrusted project
java -version
gradle --version
mkdir gradle-bootstrap-checkpoint
cd gradle-bootstrap-checkpoint
export GRADLE_USER_HOME="$PWD/.checkpoint-gradle-home"
mkdir -p evidence
java -version 2>evidence/java-version.txt || true
gradle --version >evidence/system-gradle-version.txt
Expected chapter assumptions: trusted bootstrap Gradle 9.7.1, Gradle runtime JDK 21 (or another supported 17–26 JVM), Java project target 17. Do not proceed if the bootstrap Gradle binary/source is untrusted.
3. Predict state changes before running Init
Write these predictions into
evidence/predictions.txt before executing commands:
- Build Init will create settings/build/source and Wrapper files in the repository; the isolated User Home will gain Gradle cache/daemon/Wrapper state.
-
After the first verified Wrapper build,
build/and project.gradle/will exist, while Wrapper distributions/dependency caches remain under the isolated User Home. - Changing settings to include a nonexistent project should alter/fail the settings-derived project model before normal compilation, without requiring cache deletion.
4. Bootstrap once, then harden the Wrapper
gradle init \
--type java-application \
--dsl kotlin \
--test-framework junit-jupiter \
--package dev.academy.checkpoint \
--project-name gradle-bootstrap-checkpoint \
--no-split-project \
--java-version 17 \
--use-defaults \
--no-incubating
gradle :wrapper \
--gradle-version 9.7.1 \
--distribution-type bin \
--gradle-distribution-sha256-sum acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a
cp gradle/wrapper/gradle-wrapper.properties evidence/wrapper.properties.txt
sha256sum gradle/wrapper/gradle-wrapper.jar > evidence/wrapper-jar.sha256.txt
From this point onward, the system gradle command is
evidence/repair tooling only. The project build contract is the
Wrapper.
5. Verify the Wrapper before project-owned execution
grep -F 'gradle-9.7.1-bin.zip' gradle/wrapper/gradle-wrapper.properties
grep -F 'distributionSha256Sum=acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a' gradle/wrapper/gradle-wrapper.properties
test "$(sha256sum gradle/wrapper/gradle-wrapper.jar | awk '{print $1}')" = "7a9ce74cff467ca1bf60a4fcd9f05185acceda4d0f382434d393e17864262c5d"
echo 'Wrapper metadata and JAR checksum verified' | tee evidence/wrapper-verification.txt
These checks are independent: the properties file pins the distribution identity/checksum; the local JAR digest proves the executable Wrapper JAR matches the official release checksum.
6. Capture Wrapper/JVM identity and compare accidental system invocation
./gradlew --version | tee evidence/wrapper-gradle-version.txt
gradle --version > evidence/accidental-system-gradle-version.txt
diff -u evidence/system-gradle-version.txt evidence/accidental-system-gradle-version.txt || true
The system command may happen to match 9.7.1 today. That does not make it a repository contract. The evidence exists to show what would drift if the system package changed tomorrow.
7. Read the model before building
./gradlew -q projects | tee evidence/projects-before.txt
./gradlew tasks --all --console=plain > evidence/tasks.txt
./gradlew help --task build --console=plain > evidence/build-task-help.txt
printf '%s
' '--- settings ---' > evidence/build-inputs.txt
cat settings.gradle.kts >> evidence/build-inputs.txt
printf '%s
' '--- build ---' >> evidence/build-inputs.txt
cat build.gradle.kts >> evidence/build-inputs.txt
This establishes the declared project and task surface before compilation. If a later failure changes project discovery, you have a before snapshot.
8. Build/test and verify filesystem consequences
./gradlew clean test build --console=plain | tee evidence/build.log
find build -maxdepth 3 -type f | sort > evidence/build-files.txt
find .gradle -maxdepth 3 -type d 2>/dev/null | sort > evidence/project-gradle-state.txt
find "$GRADLE_USER_HOME" -maxdepth 3 -type d | sort > evidence/user-home-state.txt
find build/test-results -type f -name '*.xml' -print | tee evidence/test-result-files.txt
find build/libs -type f -print | tee evidence/artifacts.txt
Now compare reality with your predictions. The project’s
compiled/test/archive outputs belong in build/; Wrapper
distributions and dependency caches belong under the isolated Gradle
User Home; project-specific incremental state belongs under
.gradle/.
9. Inject one safe settings failure and preserve the original cause
cp settings.gradle.kts evidence/settings.gradle.kts.good
printf '
include("missing-module")
' >> settings.gradle.kts
set +e
./gradlew -q projects >evidence/projects-broken.log 2>&1
broken_rc=$?
set -e
printf 'broken_exit=%s
' "$broken_rc" | tee evidence/broken-exit.txt
sed -n '1,120p' evidence/projects-broken.log
# Repair from the preserved known-good source.
cp evidence/settings.gradle.kts.good settings.gradle.kts
./gradlew -q projects | tee evidence/projects-repaired.txt
Gradle 9 requires included project directories to exist and be writable. The missing project changes the settings-derived build model; it is not a dependency-cache problem. The repair restores settings. No cache deletion is involved.
10. Independent fresh-home verification
mkdir -p .second-gradle-home
GRADLE_USER_HOME="$PWD/.second-gradle-home" ./gradlew test build --console=plain | tee evidence/second-home-build.log
sha256sum build/libs/* > evidence/artifact-sha256.txt
This run proves the project is not depending on hidden configuration
in the first isolated User Home. It may still use project-local
output/up-to-date state unless you run clean; if you
are validating a clean-room production artifact, use a fresh
workspace as well. This checkpoint’s purpose is bootstrap/home
isolation, not the full reproducibility exercise already taught in
Chapter 13.
11. Verification checklist
- Wrapper version is exactly 9.7.1 and runtime JVM is documented.
-
distributionUrlanddistributionSha256Summatch reviewed official values. - Wrapper JAR SHA-256 matches the official 9.7.1 value.
-
All normal discovery/test/build commands use
./gradleworgradlew.bat. - System Gradle identity is recorded only as contrast/bootstrap evidence.
-
Settings and build scripts are distinguishable from project
.gradle,build/, and User Home state. - The missing-module settings failure is captured, interpreted, repaired, and independently verified.
- No normal user Gradle home, credential store, global init script, or production repository was modified.
12. Cleanup and rollback
./gradlew --stop || true
rm -rf .second-gradle-home
cd ..
rm -rf gradle-bootstrap-checkpoint
Because every mutable home/cache/output was created under the disposable directory, cleanup has a precise blast radius. In a real repository, you would commit the verified Wrapper and build definitions rather than deleting them; this lab deletes everything only because the entire project was synthetic.
13. What Chapter 15 adds to the production build-engineering model
You can now identify Gradle’s bootstrap chain before learning its richer DSL and lazy model: repository-owned Wrapper → verified Gradle distribution → supported runtime JVM → settings-defined build structure → build-script-defined project/tasks → generated output plus explicitly scoped cache/user-home state.
Chapter 16 moves from bootstrap to authoring: Groovy DSL and Kotlin DSL, properties, Providers, lazy configuration, and build logic. The Wrapper identity established here remains the interpreter for every later Gradle concept.
Knowledge check
Why is a matching system Gradle version still not a substitute for the Wrapper?
Because the matching installation is an external coincidence that can change independently of the repository. The Wrapper is reviewed, version-pinned repository state.
The build succeeds with the first isolated User Home but fails with the second. What does that prove?
It strongly implicates hidden/configured state in the first User Home, such as init scripts, properties, caches, or provisioning. Compare those states before changing project logic.
Why does adding include("missing-module") test
settings rather than compilation?
The settings script defines project structure during initialization. Gradle must discover/configure the included project before normal compile tasks can run.
What two SHA-256 checks serve different trust purposes in the checkpoint?
distributionSha256Sum verifies the downloaded
Gradle distribution ZIP; the separate Wrapper-JAR checksum
verifies gradle-wrapper.jar itself.
Should CI cache the entire isolated Gradle User Home and treat a restored build as authoritative?
No. Cache scope/writers and content types must be controlled. Dependency/cache reuse can accelerate builds, but generated outputs and cache hits are not provenance by themselves.
What is the natural next topic after bootstrap?
Build authoring: Kotlin/Groovy DSL, properties, Providers, lazy configuration, and build logic in Chapter 16.
Official references and version notes
- Gradle 9.7.1 Release Notes — 9.7.1 is the August 19, 2026 patch release recommended over 9.7.0.
- Gradle Wrapper — Wrapper files, generation, distribution URL, checksum verification, and upgrade behavior.
- Gradle distribution and Wrapper JAR checksums — official SHA-256 reference.
- Compatibility Matrix — Gradle 9.7.1 runtime JVM support.
- Build Init Plugin — supported project types and non-interactive init options.
-
Gradle-managed Directories and Caches
— Gradle User Home, project
.gradle, build outputs, daemon logs, and dependency caches. - Gradle Daemon — client JVM, daemon JVM, status, logs, and daemon JVM criteria.
- Settings File Basics and Build File Basics.
Version snapshot: These lessons were generated for August 24, 2026 with Gradle 9.7.1 as the pinned lab release. Re-check the official release and compatibility pages before copying version-specific pins into a future production repository.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.