Builds a slimmed-down ApprovalTests jar that contains only the code your project actually uses.
flowchart LR
code["Your project's<br/>.java files"]
json["approvaltests-selection.json<br/>what you use"]
jar["approvaltests-31.0.0-custom.jar<br/>252 KB instead of 948 KB<br/>+ report.html"]
code -- "CreateSelectionJson.sh" --> json
json -- "CreatePartailApprovals.sh" --> jar
From your project's folder:
../ApprovalTests.Java.Minimizer/CreateSelectionJson.sh # 1. find what you use → approvaltests-selection.json
../ApprovalTests.Java.Minimizer/CreatePartailApprovals.sh # 2. build the slim jar → target/approvaltests-custom/You develop against the full ApprovalTests jar as usual. When you release, this tool builds a custom jar from your usages and removes everything else by Tree Shaking. For the StarterProject on 31.0.0, the jar goes from 948 KB to 252 KB, and Jackson, XStream, Quartz and others drop out. On the latest master it's 223 KB, and Velocity is gone too. See the sample report.
- Java 17+ and Maven, to run the tool
git, plus network access to clone ApprovalTests.Java- A Maven project (
pom.xml) for the project you want to slim down
Run these from your project's folder. The paths below assume this repo is cloned next to your project.
../ApprovalTests.Java.Minimizer/CreateSelectionJson.shThis scans every .java file from the current folder down and writes approvaltests-selection.json. That file lists the ApprovalTests version and every method, constructor, field and class you use. Commit it with your project.
{
"approvaltestsVersion": "31.0.0",
"entryPoints": [
"org.approvaltests.Approvals.verify(java.lang.String)",
"org.approvaltests.JsonApprovals.verifyAsJson(java.lang.Object)",
"org.approvaltests.reporters.DiffReporter.INSTANCE",
"..."
],
"runtimeDiscoveries": { "*": "keep" },
"output": { "directory": "target/approvaltests-custom", "version": "31.0.0-custom", "...": "..." }
}Check anything listed under "Could not resolve" by hand. Rerunning it later updates the version and entry points, and keeps your runtimeDiscoveries and output settings.
../ApprovalTests.Java.Minimizer/CreatePartailApprovals.shThis clones ApprovalTests at your version's tag, removes everything your selection doesn't reach, and builds. It writes these to target/approvaltests-custom/:
approvaltests-<version>-custom.jar:approvaltestsandapprovaltests-utilin one jar (sources included)approvaltests-<version>-custom-report.html: what was removed and why (see the sample report)
Run your tests with the partial jar in place of the real ones:
mvn test -Dmaven.test.dependency.excludes=com.approvaltests:approvaltests,com.approvaltests:approvaltests-util \
-Dmaven.test.additionalClasspath=$PWD/target/approvaltests-custom/approvaltests-31.0.0-custom.jarIf something is missing, it fails with NoSuchMethodError or NoClassDefFoundError. Add the missing entry point to approvaltests-selection.json and rebuild.
| Command | What it does |
|---|---|
CreatePartailApprovals.sh --current |
Builds from the latest master on GitHub instead of the release tag. Use it to try fixes before they are released. |
CreatePartailApprovals.sh explain <class or package> |
Prints why each matching class was kept, as a chain back to one of your entry points. |
CreatePartailApprovals.sh explain --current <class or package> |
The same, against the latest master. |
Example:
$ CreatePartailApprovals.sh explain com.spun.util.database.ResultSetWriter
com.spun.util.database.ResultSetWriter is kept because:
com.spun.util.database.ResultSetWriter <- referenced in its body
org.approvaltests.writers.ResultSetApprovalWriter.writeReceivedFile(File) <- it is @Override
...
org.approvaltests.JsonApprovals.verifyAsJson(Object) <- entry point org.approvaltests.JsonApprovals.verifyAsJson(java.lang.Object)
- Unused code is deleted, not stubbed. The partial jar is a drop-in replacement only for what you selected. Develop against the full jar, and release with the partial one.
- Imports count as usage. Java needs every imported class to exist, so the detector includes unused imports. Remove them if you don't want those classes.
- Runtime discoveries are all kept for now (
"*": "keep"), e.g. reporter auto-detection and test-framework detection. - Where the code is: the ApprovalTests checkout lives in this repo's
.local/folder (gitignored). Rungit -C .local/approvaltests-<version> diffto see exactly what was removed. - Gradle projects aren't supported by
CreateSelectionJson.shyet.
./build_and_test.shbuilds and tests the tool.TreeShakerTestuses a sibling../ApprovalTests.Javaclone if there is one, and clones from GitHub otherwise.- internal_documentation/PartialEvaluation.md is the spec and the current implementation notes.
- internal_documentation/architecture.md has the architecture diagrams.
- internal_documentation/processes/ has the processes: commit notation, code style, test style, fixing issues, upgrading dependencies.
docs/is published with GitHub Pages and holds the sample report (source).- AGENTS.md has the conventions for working in this repo.