Chapter 15Lesson 05~210 minutes

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.

CheckpointVerified WrapperIsolated User HomeEvidenceRollback

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, and build/.
  • 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:

  1. Build Init will create settings/build/source and Wrapper files in the repository; the isolated User Home will gain Gradle cache/daemon/Wrapper state.
  2. After the first verified Wrapper build, build/ and project .gradle/ will exist, while Wrapper distributions/dependency caches remain under the isolated User Home.
  3. 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.
  • distributionUrl and distributionSha256Sum match reviewed official values.
  • Wrapper JAR SHA-256 matches the official 9.7.1 value.
  • All normal discovery/test/build commands use ./gradlew or gradlew.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?

The build succeeds with the first isolated User Home but fails with the second. What does that prove?

Why does adding include("missing-module") test settings rather than compilation?

What two SHA-256 checks serve different trust purposes in the checkpoint?

Should CI cache the entire isolated Gradle User Home and treat a restored build as authoritative?

What is the natural next topic after bootstrap?

Official references and version notes

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.