Skip to content

Commit 90be272

Browse files
brunoborgesCopilot
andauthored
docs: document seeding the Maven cache for plugin dependencies (#1094)
* docs: document Maven cache seeding for plugin dependencies (#990) Explain that setup-java's maven cache only stores what a run downloads and is not re-saved on a hit, so plugin dependencies resolved lazily (e.g. by maven-shade-plugin) can be missing from the cache. Document a dependency resolution 'seed' step (dependency:go-offline + dependency:resolve-plugins) in README and a fuller advanced-usage section with a goal-comparison table, single-job and separate-seed-job examples, and caveats. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: note gradle cache has the same limitation, point to setup-gradle (#990) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: shorten README maven cache note, link to advanced docs (#990) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: cover the parallel multi-job cache race in the seed-job example (#705) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 3157986 commit 90be272

2 files changed

Lines changed: 119 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,13 @@ steps:
190190
run: mvn -B package --file pom.xml
191191
```
192192

193+
> [!NOTE]
194+
> Maven resolves plugin dependencies lazily, so a cache created by a "thin" goal
195+
> (e.g. `mvn compile`) can be missing plugin dependencies that later
196+
> `test`/`verify`/`package` jobs then re-download on every run. See
197+
> [Ensuring the Maven cache is complete](docs/advanced-usage.md#ensuring-the-maven-cache-is-complete-plugin-dependencies)
198+
> for how to seed a complete cache.
199+
193200
#### Caching sbt dependencies
194201
```yaml
195202
steps:

‎docs/advanced-usage.md‎

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Tencent Kona](#Tencent-Kona)
1616
- [Installing custom Java package type](#Installing-custom-Java-package-type)
1717
- [JavaFX Maven project](#JavaFX-Maven-project)
18+
- [Ensuring the Maven cache is complete (plugin dependencies)](#ensuring-the-maven-cache-is-complete-plugin-dependencies)
1819
- [Installing custom Java architecture](#Installing-custom-Java-architecture)
1920
- [Installing JDK without setting as default](#Installing-JDK-without-setting-as-default)
2021
- [Installing custom Java distribution from local file](#Installing-Java-from-local-file)
@@ -285,6 +286,117 @@ To run the JavaFX application in CI:
285286
run: mvn --no-transfer-progress javafx:run
286287
```
287288

289+
## Ensuring the Maven cache is complete (plugin dependencies)
290+
291+
When you enable `cache: maven`, the action caches your local Maven repository
292+
(`~/.m2/repository`) keyed on a hash of your `pom.xml` files, and — at the end of
293+
the job — saves whatever was downloaded during that run. It does **not** re-save
294+
the cache when the key already matches (a cache *hit*).
295+
296+
Maven resolves **plugin** dependencies lazily: it only downloads the plugins and
297+
plugin dependencies required by the goals that actually execute. As a result, the
298+
run that first creates the cache determines what is stored. If that run executed a
299+
"thin" goal such as `mvn compile`, plugins bound to later phases are never
300+
resolved. For example, `maven-shade-plugin` (bound to `package`) pulls in
301+
`plexus-archiver`, `commons-compress`, `io.airlift:aircompressor` and
302+
`org.tukaani:xz` — none of which a `compile` run downloads. Those artifacts are
303+
therefore absent from the cache, and because the action does not re-save on a
304+
hit, every later `test`/`verify`/`package` job re-downloads them on every run.
305+
306+
### Seed the cache with a resolution step
307+
308+
To populate `~/.m2` as comprehensively as possible on the run that creates the
309+
cache, run a dependency-resolution "seed" command before your build. Choose a
310+
command based on how thorough you need it to be:
311+
312+
| Seed command | Resolves plugin dependencies? | Notes |
313+
|--------------|:-----------------------------:|-------|
314+
| `mvn dependency:resolve` | No | Resolves project dependencies only — misses plugin dependencies (e.g. `aircompressor`). |
315+
| `mvn dependency:resolve-plugins` | Yes | Resolves plugins **and their dependencies**. |
316+
| `mvn dependency:go-offline` | Yes | Resolves project and plugin dependencies (a superset). |
317+
| `mvn dependency:go-offline dependency:resolve-plugins` | Yes (most thorough) | Recommended default. Use `dependency:resolve dependency:resolve-plugins` if `go-offline` is flaky or insufficient for your project. |
318+
319+
Single job — seed, then build (the cache saved at the end of this run contains
320+
the full set):
321+
322+
```yaml
323+
steps:
324+
- uses: actions/checkout@v6
325+
- uses: actions/setup-java@v5
326+
with:
327+
distribution: 'temurin'
328+
java-version: '25'
329+
cache: 'maven'
330+
- name: Seed the Maven cache
331+
run: mvn -B dependency:go-offline dependency:resolve-plugins
332+
- name: Build with Maven
333+
run: mvn -B verify --file pom.xml
334+
```
335+
336+
Separate seed job — useful for a matrix where different legs run different goals
337+
(`test`, `check`, `verify`, `-Pprofile1`, ...) but all share the same `~/.m2`
338+
cache. Without a seed, whichever job finishes first creates the cache from its
339+
own partial `.m2`, and parallel jobs race to save an equally partial cache; the
340+
seed job instead creates one comprehensive cache that every other job reuses:
341+
342+
```yaml
343+
jobs:
344+
seed-cache:
345+
runs-on: ubuntu-latest
346+
steps:
347+
- uses: actions/checkout@v6
348+
- uses: actions/setup-java@v5
349+
with:
350+
distribution: 'temurin'
351+
java-version: '25'
352+
cache: 'maven'
353+
- name: Seed the Maven cache
354+
run: mvn -B dependency:go-offline dependency:resolve-plugins
355+
356+
build:
357+
needs: seed-cache
358+
runs-on: ubuntu-latest
359+
strategy:
360+
matrix:
361+
goal: ['test', 'verify', 'test -Pprofile1']
362+
steps:
363+
- uses: actions/checkout@v6
364+
- uses: actions/setup-java@v5
365+
with:
366+
distribution: 'temurin'
367+
java-version: '25'
368+
cache: 'maven'
369+
- name: Build
370+
run: mvn -B ${{ matrix.goal }} --file pom.xml
371+
```
372+
373+
### Caveats
374+
375+
- **The seed only helps on the run that creates the cache.** Once a cache exists
376+
for the current `pom.xml` hash, later runs get a hit and any additional
377+
downloads are not saved. On an existing repository whose cache is already
378+
incomplete, invalidate it once (for example by changing `cache-dependency-path`
379+
or deleting the repository's caches) so a complete cache is created from the
380+
seed.
381+
- **Static resolution is not exhaustive.** `go-offline`/`resolve-plugins` resolve
382+
the statically declared plugin set for the *active* profiles and modules.
383+
Profile-gated plugins, conditionally-active modules, and artifacts a plugin
384+
fetches at execution time may still be missed. For the most complete cache,
385+
seed with the fullest goal set your CI actually uses (for example
386+
`mvn -B verify` with every profile enabled).
387+
- **Multi-module projects:** run the seed at the reactor root so every module's
388+
plugins are resolved.
389+
390+
> [!NOTE]
391+
> The same "the cache stores only what the creating run downloaded, and is not
392+
> re-saved on a hit" behavior applies to `cache: gradle`, since Gradle also
393+
> resolves dependencies and plugin/buildscript classpaths lazily. Gradle has no
394+
> direct equivalent of `dependency:go-offline`, so for complete and fine-grained
395+
> dependency caching on Gradle projects we recommend
396+
> [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle),
397+
> which provides purpose-built caching (see the
398+
> [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md)).
399+
288400
## Installing custom Java architecture
289401

290402
```yaml

0 commit comments

Comments
 (0)