Follow-up to #1069, which bumped the
`github-dependency-graph-gradle-plugin` default to `1.5.0`.
`1.5.0` is signed with a **new** Gradle signing subkey, and the key
currently documented in `docs/setup-gradle.md` has been revoked
upstream. Without this docs change, the snippet we publish will fail
dependency verification for Dependency Graph generation.
I verified the published signatures rather than relying on the
changelog:
| Artifact | Issuer key | |
|---|---|---|
| `github-dependency-graph-gradle-plugin:1.5.0` | `D9B2DFBD9F3298BA` |
new |
| `github-dependency-graph-gradle-plugin:1.4.2` | `893A028475557671` |
old |
| `develocity-gradle-plugin:4.5.0` | `893A028475557671` | old |
So the docs now list **both** keys instead of swapping one for the
other. The Develocity Gradle plugin (`com.gradle`) is still signed with
the old key, so replacing it outright would have broken Develocity
injection for builds with dependency verification enabled.
Docs-only change; no source or `dist` impact.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Updates the default version of the [GitHub Dependency Graph Gradle
Plugin](https://plugins.gradle.org/plugin/org.gradle.github-dependency-graph-gradle-plugin)
applied by the `dependency-submission` init-script from `1.4.2` to
`1.5.0`.
`1.5.0` is the latest version published to the Gradle Plugin Portal.
Users can still override this via the `dependency-graph-plugin.version`
input parameter (`DEPENDENCY_GRAPH_PLUGIN_VERSION`), so this only
changes the default.
## Notes
The init-script is read at runtime from `sources/src/resources` rather
than being inlined into the bundle, so this single source change is the
whole fix — no `dist` update is needed for the new version to take
effect (CI refreshes `dist` as usual).
## Verification
- `npm run check` (prettier + eslint) passes
- `npm run test`: 489 passed. The 2 failing wrapper-validation suites
are pre-existing network-dependent failures on this machine — confirmed
identical on a clean tree with this change stashed
- Confirmed `1.5.0` is published to the plugin portal (and that a bogus
version 404s, so the check is meaningful)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Combines three pending automated update PRs into a single pull request
so they can be reviewed and merged together.
Supersedes:
- #1045 — Update known wrapper checksums
- #1066 — Bump the npm-dependencies group in /sources (eslint 10.9.1 →
10.10.0, globals 17.11.0 → 17.12.0)
- #1067 — Bump actions/setup-java from 5.7.0 to 6.0.0 in the
github-actions group
Each original commit is cherry-picked unchanged; there were no
overlapping files or conflicts.
## Verification
- `./build install` (clean install + format + lint + compile) passes.
- `./build test`: 490/491 pass. The single failure is
`wrapper-validation/checksums.test.ts › fetches wrapper jar checksums
for snapshots`, a pre-existing network-dependent failure on this machine
— it fails identically with `main`'s checksums file, so it is unrelated
to these changes.
- `dist/` is intentionally untouched; CI regenerates it.
---------
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: bot-githubaction <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
The pins in `.tool-versions` had drifted well behind what CI and the
Gradle wrappers use. One of
them was not just stale but broken.
## node 24.3.0 → 24.18.0
CI runs `node-version: 24`, which resolves to a much newer 24.x. That
gap is not harmless: it
recently masked a real CI failure outright, because jest 30.5.0's
breakage of nock interception
reproduces on 24.18.0 but not on 24.3.0. A local run that passes is
worth something again.
Verified with a clean `./build install` and repeated `./build test` runs
on both versions. Both show
the same stable core of two failures — the network-dependent
wrapper-validation checksum tests —
plus an occasional third flake in the same area that varies between runs
and between node versions.
Nothing attributable to the bump.
## java liberica-11 → liberica-17
This pin was broken. The init-scripts wrapper is on Gradle 9.7.1, which
refuses to run a build on
JVM 11:
```
Gradle requires JVM 17 or later to run.
Your build is currently configured to use JVM 11.
```
So `./build init-scripts` could not have worked with the pinned
toolchain. `./gradlew --version`
*does* start under JVM 11 and reports successfully, which is likely how
the pin survived unnoticed —
only an actual build fails.
17 matches what `ci-init-script-check.yml` provisions, so local runs
mirror CI. Verified with a
clean `./gradlew check` in `sources/test/init-scripts`: BUILD SUCCESSFUL
in 3m57s.
Java 21 was also tried and passes (3m53s), so moving further later is
unblocked. 17 is chosen only
to track CI.
## gradle 8.14.2 → 9.7.1
Follows the wrappers, which the workflow samples and init-scripts tests
are now on. This matches how
the file has been maintained before (e.g. "Use Gradle 8.14 everywhere").
Nothing in `./build`
invokes the asdf gradle — every path goes through `./gradlew` — so this
only keeps ad-hoc CLI use
consistent.
## Notes
`ci-check-and-unit-test.yml` still provisions `gradle-version: '8.14.2'`
for its unit-test job.
That may be equally stale, but it is a CI behaviour change rather than
local tooling, so it is left
alone here.
One flaky run was seen while verifying: two `TestDevelocityInjection`
cases against Gradle 6.0.1
failed once, then passed on re-run and on repeat clean builds. Unrelated
to these version changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Rolls the outstanding dependency updates into a single change, along
with fixes for two breaking
changes they brought with them.
## Gradle Wrapper 9.6.1 → 9.7.1
Updated in all five wrapped projects: `sources/test/init-scripts` and
the `gradle-plugin`,
`groovy-dsl`, `java-toolchain` and `kotlin-dsl` workflow samples.
## GitHub Actions
- `actions/setup-java` v5.7.0 → v6.0.0
- `github/codeql-action/init` and `github/codeql-action/analyze`
re-pinned to a newer v3.29.5 commit
## npm dependencies
- `@typescript-eslint/eslint-plugin` 8.66.0 → 8.69.0
- `esbuild` 0.28.1 → 0.28.2
- `eslint` 10.8.0 → 10.9.1
- `globals` 17.9.0 → 17.11.0
`jest` stays at 30.4.2 and `@jest/globals` at 30.4.1 — see below.
## setup-java v6 needs signature verification disabled for EOL JDKs
v6 enables `verify-signature` by default. Temurin 16 and 20 are EOL and
publish no signatures, so
the toolchain-detection job could no longer install them:
```
Java setup process failed due to: Input 'verify-signature' is enabled,
but no signature URL was found for Temurin version 16.0.2+7.
```
Verification is disabled for those two steps only. The Java 17 and
matrix steps still verify.
## jest is held at 30.4.x because 30.5.0 breaks nock
jest 30.5.0 reworked the ESM module registry (ES modules keyed by full
URL, modules shared across
overlapping CommonJS/ESM graphs). nock ends up patching a different
module instance than the one
`@actions/http-client` reaches undici through, so it no longer
intercepts anything: all five mocked
tests in `short-lived-token.test.ts` silently hit the real network and
resolve `null`. Two further
tests in that file keep passing only vacuously — they assert `null`,
which is also what an
unintercepted request returns.
Bisected on node 24.18.0, changing only the jest version:
| jest | result |
| --- | --- |
| 30.5.0 | 5 failed, 38 passed |
| 30.4.2 | 43 passed |
nock 15.0.0 does not fix it, so this cannot be resolved by moving nock
forward. The node version
matters too: 24.3.0 masks the failure completely, which is why it
reproduced only in CI.
Because `jest` is an exactly-pinned direct devDependency, the pin by
itself holds the entire test
runtime at 30.4.x — `jest-cli`, `jest-runtime`, `jest-environment-node`,
`@jest/core`,
`@jest/transform`, `@jest/types`, `expect` and `jest-util` all resolve
to 30.4.x with no `overrides`
block. Nothing in the tree forces jest forward; only dependabot proposes
it. So the constraint is
expressed in `.github/dependabot.yml`, alongside the existing
`typescript` and `@types/node`
entries, ignoring `jest` and `@jest/globals` `>=30.5.0` with a comment
recording when it can be
lifted.
`pretty-format` is left to float to 30.5.1 via the types-only
`@types/jest`; it renders test output
and has no bearing on nock or module resolution.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: bot-githubaction <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: bot-githubaction <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
This PR reports the support status of every Gradle version used in a
workflow:
- **End-of-life** — two or more major versions behind the latest
release.
- **Out of date** — one major version behind the latest release, or more
than two minor versions behind on the current major.
The information is surfaced as job annotations and in the Job Summary:
an icon beside the Gradle version in the build results table, and a
message below it.
| version kind | job annotation | version table | below the table |
| ------ | ----- | ---- | --------- |
| EOL | warning | ⚠️ | expandable section, pointing to the Gradle
Security Subscription |
| Out of date | notice | ℹ️ | one-line legend, pointing to the Gradle
release lifecycle docs |
| Current | none | — | — |
A single expandable section covers every end-of-life version, naming
them in its summary line and listing the affected release lines in its
body. The upgrade legend likewise appears once per job, however many
versions carry the info icon.
Notes on what is deliberately *not* reported:
- **Patch releases.** Only the major and minor version are considered,
so being on `9.7.0` when `9.7.1` exists is not flagged.
- **Pre-releases.** Release candidates, milestones and snapshots are
never reported, so testing against a nightly or an RC produces no
annotations.
The latest Gradle release is determined from the wrapper checksum data
already bundled with the action, so no network access is required. That
data is refreshed weekly, and the two-minor grace band absorbs the lag.
Note that the annotations are emitted independently of
`add-job-summary`: setting it to `never` suppresses the Job Summary
itself, but the warning and notice annotations remain.
### Examples
The `demo-job-summary` workflow has a `support-status-eol-and-outdated`
job that builds with three end-of-life versions (`6.9.4`, `7.4`,
`7.6.6`), two out-of-date versions (`8.0.2`, `8.14.5`) and the current
release, so all three statuses appear in one summary:
* **Job Summary**:
https://github.com/gradle/actions/actions/runs/34166688755#summary-101879071306
* **Annotations**:
https://github.com/gradle/actions/actions/runs/34166688755/job/101879071306
(expand annotations)
That workflow is never triggered automatically; run it manually against
a branch to review the rendering.
### Implementation
* Adds `GradleVersion`, parsing and ordering versions the same way
Gradle's own `org.gradle.util.GradleVersion` does. This replaces the
previous `versionIsAtLeast` helper and removes the `semver` dependency.
* Adds `gradle-support-status.ts`, which owns the classification policy
and both of its presentations (annotations and Job Summary section)
behind a three-function API, so `job-summary.ts` only asks for the icon
and the rendered block.
### Testing
* Unit tests for version ordering, classification, the annotations and
the rendered summary.
* `integ-test-gradle-support-status.yml`, which derives its expected
versions from the bundled release data so the assertions cannot drift
from the action's own view, then asserts against the real job log.
* The demo workflow job linked above, for reviewing the rendering by
eye.
Documented under [Build
reporting](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md#gradle-version-support-status)
in `docs/setup-gradle.md`.
---------
Co-authored-by: Louis Jacomet <[email protected]>
Co-authored-by: Daz DeBoer <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Replaces the unqualified `wrapper` task name with the
root-project-qualified
`:wrapper` in the two places this repo names it:
- `.github/workflows/demo-job-summary.yml` — the kotlin-dsl sample
invocation
- `docs/wrapper-validation.md` — the guidance for regenerating an
unverifiable
`gradle-wrapper.jar`
An unqualified `wrapper` matches the task in every project of a
multi-project
build. The root-qualified form is unambiguous, matches the gradle/gradle
convention, and is required under Configure on Demand.
Part of the org-wide rollout tracked in gradle/gradle-private#5228;
original
issue gradle/gradle#37761.
Signed-off-by: Christoph Obexer <[email protected]>
Develocity access keys have the format `server=key[;server=key]*`. The
short-lived-token code validated that format with:
```
/^([^;=\s]+=\w+)(;[^;=\s]+=\w+)*$/
```
This is too strict about `key`, and an OIDC token value fails it. There
were two independent problems:
1. `\w+` rejects the `.`, `-`, `_` and `=` padding a JWT contains.
2. Even had the regex passed, `parse` split each entry with
`hostKey.split('=')` and took `pair[1]`, so a key containing `=` would
have been **silently truncated** — a worse failure than rejection, since
the mangled key would then be sent to the server.
## Change
Drop `accessKeyRegexp` and the separate `isValid` gate; validate
structurally in `parse` instead, asserting only what is needed to split
the value:
- split on `;`, then split each entry on its **first** `=` only
- hostname: non-empty and free of whitespace (it cannot contain `=` or
`;` by construction)
- key: non-empty and free of whitespace — nothing else is assumed about
its shape
Two small intentional behaviour deltas beyond the fix:
- The whole value is now trimmed, so a trailing newline on a secret no
longer rejects the key. Internal whitespace still rejects.
- Empty entries (`host=key;`, `;host=key`) still reject, as before.
## Testing
Added cases to `short-lived-token.test.ts`: a JWT-shaped key value,
first-separator-only splitting (`host1=a=b==` → key `a=b==`),
surrounding-whitespace tolerance, a `raw()` round-trip preserving `==`
padding, and a table of nine rejection cases. 32 tests pass; prettier,
eslint and `./build` are clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Users relying on an external mechanism to save/restore Gradle User Home
(e.g. Develocity Artifact Cache) previously had to set cache-disabled:
true, which is confusing since caching isn't actually disabled — it's
just not managed by this action — and the Job Summary misleadingly
reported caching as "Disabled".
cache-provider: external skips Gradle User Home restore/save (same as
cache-disabled) but reports a distinct "External" status in the Job
Summary, explaining that caching is handled by another provider.
---------
Co-authored-by: Claude Sonnet 5 <[email protected]>
Job summaries from setup-gradle/dependency-submission had no top-level
heading, so they read poorly when another action's summary content lands
in the same job. Name the action explicitly so the block is attributable
when summaries are stacked.
---------
Co-authored-by: Claude Sonnet 5 <[email protected]>
Release immutability is now enabled for this repository, so a published
release permanently locks its Git tag to a commit, and deleting the
release does not free the tag name for reuse.
Reorder the steps so the signed tag is created and pushed before the
release is drafted, and have the draft select that existing tag. Letting
GitHub create the tag at publish time produces an unsigned, lightweight
tag pointing at whatever main resolves to at that moment - both of which
immutability then makes permanent.
Also record that the v6 major tag must never have a release attached:
immutability locks only tags that have a release of their own, which is
what keeps the conventional major-tag force-push legal.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Previously handled via `@dependabot ignore` issue comments, which don't
provide enough control. Declaring the rules in the config makes them
explicit and reviewable.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Consolidates seven open bot PRs into three commits.
## 1. Bump Gradle Wrapper from 9.5.1 to 9.6.1
Combines **#1008, #1009, #1010, #1011, #1012** into a single commit.
Each of those PRs bumped the wrapper in one directory; this covers all
five (15 files):
- `sources/test/init-scripts`
- `.github/workflow-samples/gradle-plugin`
- `.github/workflow-samples/groovy-dsl`
- `.github/workflow-samples/java-toolchain`
- `.github/workflow-samples/kotlin-dsl`
Each location gets the same `distributionUrl` → `gradle-9.6.1-bin.zip`
and `distributionSha256Sum` update, plus the regenerated `gradlew` /
`gradlew.bat` scripts.
## 2. Update known wrapper checksums
**#990**, unchanged, as its own commit. Adds 36 checksum entries to
`sources/src/wrapper-validation/wrapper-checksums.json`, **including the
9.6.1 checksums** — which is what lets the wrapper bump above pass
`CI-validate-wrappers`. These two are worth landing together.
## 3. Bump Develocity Gradle plugin from 4.4.2 to 4.5.0
**#1015**, unchanged, as its own commit. Updates the plugin reference
across workflow samples, init-script tests, docs, and the injected
default in `sources/src/develocity/build-scan.ts`:
```diff
-maybeExportVariable('DEVELOCITY_INJECTION_DEVELOCITY_PLUGIN_VERSION', '4.4.2')
+maybeExportVariable('DEVELOCITY_INJECTION_DEVELOCITY_PLUGIN_VERSION', '4.5.0')
```
Since this touches `sources/src`, the bundled `dist/` will change when
the update-dist bot runs.
## Verification
All three cherry-picks applied without conflicts. On the combined
branch:
- `./build` — clean
- `npm run check` (prettier + eslint) — clean
- `npm test` — 373 tests, 15 suites, all passing
Original bot authorship is preserved on all three commits.
## Superseded PRs
Once this merges, these can be closed: #1008, #1009, #1010, #1011,
#1012, #990, #1015.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Co-authored-by: bot-githubaction <[email protected]>
Supersedes #1023.
## 1. Adjust dependabot's TypeScript choices
Dependabot's group bump included two changes that we don't want to take
as-is:
- **typescript**: `5.9.3` → `7.0.2`. Pinned to **6.0.3** instead.
- **@types/node**: `25.9.2` → `26.1.1`. Downgraded to the latest 24.x
(**24.13.3**), matching the Node 24 runtime the actions target.
All other updates from #1023 are kept unchanged (`@actions/cache` 6.2.0,
`semver` 7.8.5, `@typescript-eslint/eslint-plugin` 8.65.0, `esbuild`
0.28.1, `eslint` 10.7.0, `globals` 17.7.0, `prettier` 3.9.6, `ts-jest`
29.4.12), and the branch is rebased onto current `main`.
The prettier 3.9.6 bump reformats two union types in
`sources/src/cache-service.ts`; that reformatting is included so `npm
run check` passes.
## 2. Clear 5 open security advisories
`npm audit` reported 4 high and 1 low severity advisory. All are fixable
with **semver-compatible transitive updates** — `npm audit fix` clears
them without `--force`, and `package.json` is untouched.
**Production** (bundled into `dist/`, so they ship in the actions):
| Package | Before | After | Via |
| --- | --- | --- | --- |
| `undici` | 6.24.1 | 6.28.0 | `@actions/github`, `@actions/http-client`
|
| `undici` | 7.24.5 | 7.29.0 | `cheerio` |
| `brace-expansion` | 5.0.6 | 5.0.9 | `@actions/glob` → `minimatch` |
| `brace-expansion` | 2.0.3 | 2.1.4 | `@actions/artifact` → `archiver` |
**Dev only:** `shell-quote` 1.8.4 → 1.10.0 (`npm-run-all`), `js-yaml`
3.14.2 → 3.15.1 (`ts-jest`), `@babel/core` 7.28.0 → 7.29.x (`ts-jest`,
low severity).
These were outstanding because the lockfile pins transitive resolutions
while `.github/dependabot.yml` only bumps direct dependencies. Because
`undici` and `brace-expansion` are production dependencies, the bundled
`dist/` output will change when the update-dist bot runs.
## 3. Downgrade nock to 14.0.17
**nock 15.0.0 was published by mistake.** The registry marks it
deprecated:
> v15.0.0 was released accidentally and is unstable. Please use v14.x
until v15 is officially ready.
nock's `latest` dist-tag still points at 14.0.17 for exactly this
reason, and 15.x remains a beta line (`beta` = `15.0.0-beta.14`).
Dependabot picked up 15.0.0 in an earlier group bump simply because it
is the highest published version. This moves us to 14.0.17, pulling
`@mswjs/interceptors` 0.39.8 → 0.41.9 and adding `propagate` 2.0.1.
Dependabot will likely re-propose nock 15.0.0 on its next weekly run,
since no ignore rule was added.
## 4. Delete unused `sources/.nvmrc`
The file pinned Node `v16`, contradicting `package.json` engines
(`>=24.0.0`), the esbuild `node24` target, and `.tool-versions` (`nodejs
24.3.0`). Nothing reads it — no workflow uses `node-version-file` and
there are no other references in the repo. Stale since 5e522253.
## 5. Run CI workflows on Node 24
`ci-check-and-unit-test.yml`, `ci-update-dist.yml`, and
`update-checksums-file.yml` pinned `node-version: 20`, so `npm
clean-install` was emitting `EBADENGINE` warnings for the root package
against its own `engines: >=24.0.0`. All three now use Node 24, matching
`.github/actions/build-dist/action.yml`.
Worth noting: `ci-update-dist.yml` built `dist/` on Node 20 in its
inline steps while `build-dist/action.yml` built it on Node 24, so the
committed distribution could previously be produced under either
version.
## Verification
- `./build` — clean
- `npm run check` (prettier + eslint) — clean
- `npm test` — 373 tests, 15 suites, all passing
- `npm audit` — **found 0 vulnerabilities** (was 4 high, 1 low)
- `npx tsc --noEmit` — one pre-existing error in
`@octokit/request-error` types (`Cannot find name 'ErrorOptions'`),
identical on `main` with TypeScript 5.9.3, so not a regression. `tsc` is
not part of the build or CI.
A clean regeneration of `package-lock.json` from `package.json` was also
evaluated. It likewise yields 0 vulnerabilities and 373 passing tests,
but churns 80 transitive packages including the `@azure/core-*` /
`@azure/storage-blob` stack used by `@actions/cache`. Since it offers no
security benefit over the current lockfile, it was not adopted.
### Known-failing checks (pre-existing on `main`)
The three `smoke-tests / restore-gradle-home / … (windows-latest)` jobs
fail with `Build was not cached: unexpected execution of test task`. The
identical three jobs fail on `main` in run
[30723964208](https://github.com/gradle/actions/actions/runs/30723964208),
on the very commit this branch is based on, so they are not caused by
these changes.
## Not included
`npm outdated` also shows `eslint` 10.7.0 → 10.8.0 and `globals` 17.7.0
→ 17.8.0. Both are dev-only and dependabot's weekly npm group run will
propose them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Partial revert of the extraction in #1027. The caching smoke test should
answer one question quickly — does a seeded cache let a later build run
`--offline`? Everything else is integration-level.
Replaces #1031 and #1030, squashed into a single commit.
## Layout
`smoke-test-restore-gradle-home.yml` — two jobs:
| job | purpose |
|---|---|
| `restore-gradle-home-seed-build` | seed the cache |
| `restore-gradle-home-dependencies-cache` | verify the restored cache
allows `--offline` |
`integ-test-restore-gradle-home.yml` — restored, wired back into
`suite-integ-test-caching`:
| job | purpose |
|---|---|
| `restore-gradle-home-seed-build` | seed the cache (duplicated, see
below) |
| `restore-gradle-home-build-cache` | local build-cache restored |
| `restore-gradle-home-no-extracted-cache-entries-restored` | build
works with cache entries skipped |
| `restore-gradle-home-pre-existing-gradle-home` | pre-existing GUH
overwritten by restore |
This file is identical to the pre-#1027 original except for the
`dependencies-cache` job, which the smoke test now owns. All four jobs
keep the `runner-os` matrix.
## Notes
**The seed job is duplicated, with distinct cache keys.** The smoke
suite uses `smoke-test-restore-gradle-home-*`; the integ suite keeps
`restore-gradle-home-*`. This matters: `smoke-tests` and
`caching-integ-tests` run concurrently in `ci-integ-test.yml`, so
sharing a key would have both suites racing to write the same entry.
**Distinct workflow `name:`.** The smoke workflow is `Smoke test restore
Gradle Home`, so the two don't appear identically in the Actions UI.
**One thing to be aware of for the future:**
`restore-gradle-home-pre-existing-gradle-home` cannot pass on Windows.
Pre-creating `~/.gradle` is what stops `setup-gradle` relocating the
Gradle User Home to `D:\a\.gradle`, so the job looks for a cache entry
rooted at a different path than the seed build saved and never matches
it. The caching integ suite runs ubuntu-only, so this is not a problem
today — but adding Windows to that suite would surface it.
## Verification
All workflow YAML parses, and every local `uses:` reference resolves —
no dangling paths after the rename and re-add.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Follow-up to #1027, which added Windows coverage for the caching smoke
tests. `basic-cache-verify-build` failed on Windows for a reason
unrelated to #1013.
## Root cause
The Windows seed job **never uploaded a cache entry, but reported that
it did**. `gh cache list` showed no `setup-java-Windows-*` entry at all,
despite the job logging `Basic caching saved entry with key:
setup-java-Windows-x64-gradle-594edf…`. The keys were never the problem
— seed and verify requested the identical key.
The seed build leaves a Gradle daemon running, holding the `*.lock`
files in the Gradle User Home. On Windows those locks are mandatory, so
`tar` cannot read them:
```
/usr/bin/tar: ../../.gradle/caches/modules-2/modules-2.lock: Read error at byte 0,
while reading 38 bytes: Device or resource busy
/usr/bin/tar: Exiting with failure status due to previous errors
```
38 bytes is exactly Gradle's lock-file header — the region the daemon
holds via `FileChannel.lock()`. On Linux the lock is advisory and tar
reads straight through, which is why this only ever failed on Windows.
`cache.saveCache()` catches the tar failure, logs it, and returns `-1`
rather than throwing. `BasicCacheService.save()` ignored the return
value, so the seed job went green and the failure surfaced only later —
as a plugin resolution error in the verify job, pointing nowhere near
caching.
## Changes
**1. Warn when the save fails.** Check the returned `cacheId` and, when
it is `-1`, emit a warning and report `(Entry not saved: save failed)`
in the job summary. Caching failures still do not fail the build.
**2. Run the seed build with `--no-daemon`.** Daemon management for
enhanced caching lives in the `gradle-actions-caching` library; basic
caching leaves it to the workflow, so the smoke test now ensures no
daemon is holding locks when the post-action save runs.
## Not related to #1013
The enhanced provider fails differently on Windows — every entry dies at
path validation, before tar runs (`Path Validation Error: Path(s)
specified in the action for caching do(es) not exist`). Same symptom,
different mechanism; that one is unchanged here and is still expected to
be red.
## Verification
`npm run check` and `npm test` pass locally (373 tests). The real check
is this PR's Windows run: `basic-cache-seed-build` and
`basic-cache-verify-build` should both be green on `windows-latest`,
while the `restore-gradle-home-*` Windows jobs stay red pending the
#1013 fix.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
## Why
Issue #1013 revealed that caching was **never storing content on
Windows**. Nothing caught it because the integ-tests lost their multi-OS
matrices: these workflows used to default to `'["ubuntu-latest",
"windows-latest", "macos-latest"]'`, narrowed to ubuntu-only in bcd07e66
/ d74ee73e (Aug 2024). The Windows code path has been dark ever since.
## What
Extract the two cheapest caching tests — `restore-gradle-home` and
`basic-cache-provider` — into a new `suite-smoke-test-caching` workflow,
and run that suite on both `ubuntu-latest` and `windows-latest`.
Both tests seed a cache in one job and then verify it in a dependent job
with an `--offline` build, so a cache that stores nothing fails the
verify job rather than passing silently.
- Rename `integ-test-{restore-gradle-home,basic-cache-provider}` →
`smoke-test-*` and drop them from `suite-integ-test-caching`
- Add the new suite to both `CI-integ-test` and `CI-integ-test-full`,
each with its own concurrency group matching the sibling suites
- Include `smoke-tests` in the `integ-test-success` aggregate gate
- Ignore the generated `task-configured.txt` marker in
`workflow-samples`
- Drop a dead `needs.determine-suite` guard on the `build-distribution`
step — `CI-integ-test` has no such job, so it always evaluated to true
The suite runs on Windows in PR CI (not just `CI-integ-test-full`)
specifically so the failure is visible on this PR and the fix can be
verified the same way.
## Expected result
This PR is expected to be **red on Windows**.
`restore-gradle-home-dependencies-cache` and `basic-cache-verify-build`
should fail with dependency-resolution errors under `--offline` — that
is the bug from #1013 being caught. The ubuntu legs should stay green.
Cross-OS cache keys are safe: both providers include `RUNNER_OS` in the
key (`sources/src/cache-service-basic.ts:146`), so the matrix legs don't
collide.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
## Problem
The `dependency-submission` action disables Isolated Projects for the
dependency-resolution build by passing
`-Dorg.gradle.unsafe.isolated-projects=false`.
Recent Gradle versions have promoted the property to
`org.gradle.isolated-projects`. A build that enables IP via the promoted
property (e.g. `gradle/gradle`, see [this failing
run](https://github.com/gradle/gradle/actions/runs/30357651750/job/90269499556?pr=38402))
is no longer disabled by the unsafe spelling, so the build runs with IP
enabled and fails:
```
Error resolving plugin [id: 'gradlebuild.build-environment']
> Project ':build-logic-settings' cannot access 'Project.tasks' functionality on subprojects via 'allprojects'
```
(`ForceDependencyResolutionPlugin` is not IP-compatible.)
## Fix
Pass both spellings of the property. `-D` system properties that Gradle
does not recognize are silently ignored, so this is safe for all
supported Gradle versions — the action already passes the unsafe
spelling to pre-IP Gradle versions without issue.
## What's Changed
> [!IMPORTANT]
> **Cache invalidation:** The cache protocol version has been bumped to `v2`, invalidating all cache entries written by earlier releases. The first build after upgrading will not find existing caches and will repopulate them from scratch.
### Improvements
* **Consistent cache-entry names in reports** — every extracted cache entry now has a single, unique name reported identically on both restore and save. Previously the restore report could show a raw glob pattern (e.g. `caches/modules-*/files-*/*/*/*/*/`) instead of a friendly name like `dependencies`. Bundled entries are named by artifact type, per-file entries by their Gradle-User-Home-relative path, and per-project entries by `project-<rootProjectName>`.
Pass develocityAccessToken and develocityServerUrl the
`gradle-actions-caching`: required to support project-entry caching
(build-logic + configuration-cache), which has experimental support in
'[email protected]. This support is not yet released and will
be available as a restricted trial.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Render the configuration-cache restore-state in the caching Job Summary,
driven by the new `CacheReport.configurationCache` field produced by the
`gradle-actions-caching` provider.
## What's here
- `cache-service.ts`: add a `ConfigurationCacheStatus` type
(`not-active` / `restored` / `not-restored` / `restore-incomplete`) and
an optional `configurationCache` field on `CacheReport`.
- `caching-report.ts`: a `CONFIG_CACHE_COPY` map and a prominent status
line in `renderCachingReport`, beside the cleanup line. The `not-active`
case links to the `#cache-encryption-key` docs.
## Cross-repo dependency
The field is populated by gradle/actions-caching PR #75 ("Restore
configuration-cache support for simple builds"). This rendering compiles
independently (it uses this repo's own `CacheReport` type) and renders
nothing until the vendored `gradle-actions-caching` bundle is refreshed
from that branch — so this should land with/after the vendor refresh.
## Verification
`npm run check` clean; full Jest suite (366 tests) passes, including 3
new rendering tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-12 19:51:57 -06:00
114 changed files with 5571 additions and 2339 deletions
echo "Expected exactly one upgrade legend, found ${legends}"
exit 1
fi
assert_logged "<p>:information_source: Gradle version is out of date — consider upgrading. See <a href=\"https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support\">Gradle release lifecycle</a></p>"
- If new features have been added, bump the minor version (eg `4.1.1` → `4.2.0`)
- If a new major release is required, bump the major version (eg `4.1.1` → `5.0.0`)
- Note: The gradle actions follow the GitHub Actions convention of including a .0 patch number for the first release of a minor version, unlike the Gradle convention which omits the trailing .0.
- Release immutability is a one-time repository setting (Settings → General → Releases → "Enable release immutability"), and applies to every release published thereafter.
## Release gradle/actions
- Create a tag for the release. The tag should have the format `v6.2.0`
> [!IMPORTANT]
> Releases in this repository are [immutable](https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases).
> Once a release is published, its Git tag is permanently locked to a commit and its assets can no
> longer be changed. Deleting the release does not release the tag name for reuse — a mistake in
> `v6.3.0` means the next release must be `v6.3.1`. Everything below is ordered so that the tag is
> correct *before* anything is published.
>
> Drafts are exempt: a draft release, and its tag, can still be edited or deleted freely.
- Create and push the tag for the release **before** drafting it. The tag should have the format `v6.2.0`
- Your HEAD must point at the commit to be released.
- From CLI: `git tag -s -m "v6.2.0" v6.2.0 && git push --tags`
- Note that we sign the tag and set the commit message for the tag to the newly released version.
- Do **not** let GitHub create the tag when the release is published. It creates an unsigned,
lightweight tag pointing at whatever `main` resolves to at that moment — so anything merged
while the draft was open is silently included. Immutability makes both permanent.
- Go to https://github.com/gradle/actions/releases and "Draft new release"
-Use the newly created tag and copy the tag name exactly as the release title.
-Select the existing tag — do not use "Create new tag on publish" — and copy the tag name exactly as the release title.
- Craft release notes content based on issues closed, PRs merged and commits
- Include a Full changelog link in the format https://github.com/gradle/actions/compare/v2.12.0...v3.0.0
- Finalize the notes now, while the release is still a draft.
- Publish the release.
- Confirm immutability took effect: `gh api repos/gradle/actions/releases/tags/v6.2.0 --jq .immutable` should print `true`.
- Force push the `v6` tag (or current major version) to point to the new release. It is conventional for users to bind to a major release version using this tag.
- From CLI: `git tag -f -s -a -m "v6.2.0" v6 && git push -f --tags`
- Note that we sign the tag and set the commit message for the tag to the newly released version.
- Your HEAD must point at the commit to be tagged.
- Never attach a GitHub release to the `v6` tag. Immutability locks only those tags that have a
release of their own, so the major tag remains movable precisely as long as it has none.
'enhanced' (default) uses the full-featured commercial caching service (gradle-actions-caching).
'basic' uses a simple open-source caching implementation based on GitHub Actions cache.
'external' disables Gradle User Home caching by this action, for use when Gradle User Home is already saved and restored by another mechanism (e.g. Develocity Artifact Cache).
@@ -133,6 +133,7 @@ You choose which provider to use via the `cache-provider` input:
- **`enhanced`** (default): Uses the full-featured commercial `gradle-actions-caching` library. Provides advanced features like fine-grained cache entries, intelligent cache cleanup, and deduplication. See [Enhanced Caching](#enhanced-caching) for details.
- **`basic`**: A fully open-source (MIT) caching implementation built on the standard GitHub Actions cache (`@actions/cache`). Uses the same caching strategy as `actions/setup-java` with `cache: gradle`. See [Basic Caching](#basic-caching) for details.
- **`external`**: Disables Gradle User Home caching by this action, for use when another mechanism already saves and restores Gradle User Home. See [Using an external cache provider](#using-an-external-cache-provider) for details.
```yaml
# Use the open-source basic cache provider
@@ -185,7 +186,17 @@ Specifically:
- Avoid using `actions/cache` configured to cache the Gradle User Home, [as described in this example](https://github.com/actions/cache/blob/main/examples.md#java---gradle).
- Avoid using `actions/setup-java` with the `cache: gradle` option, [as described here](https://github.com/actions/setup-java#caching-gradle-dependencies).
Using either of these mechanisms may interfere with the caching provided by this action. If you choose to use a different mechanism to save and restore the Gradle User Home, you should disable the caching provided by this action, as described above.
Using either of these mechanisms may interfere with the caching provided by this action. If you choose to use a different mechanism to save and restore the Gradle User Home, you should disable the caching provided by this action, as described above, or [use `cache-provider: external`](#using-an-external-cache-provider) if that mechanism is a dedicated Gradle User Home cache.
#### Using an external cache provider
If Gradle User Home is already saved and restored by another mechanism — for example the [Develocity Artifact Cache](https://github.com/gradle/actions-caching) — set `cache-provider: external` rather than `cache-disabled: true`.
Both settings stop `setup-gradle` from restoring or saving Gradle User Home, but `cache-provider: external` reflects the actual reason: caching is still happening, just not through this action. It also updates the Job Summary to say that caching was handled externally, rather than implying that caching was turned off.
```yaml
cache-provider:external
```
## Enhanced Caching
@@ -507,6 +518,30 @@ so that a Job Summary is never generated, or so that a Job Summary is only gener
add-job-summary:'on-failure'# Valid values are 'always' (default), 'never', and 'on-failure'
```
### Gradle version support status
The Job Summary reports the support status of each Gradle version used in the workflow, and the action adds a
Job annotation for any version that is no longer current. The latest Gradle release is determined from release data
bundled with the action, so no network access is required.
A version is reported when it is:
- **End-of-life** — two or more major versions behind the latest release. Each such version is marked with :warning:
in the build results table, a single expandable section below the table explains that the affected release lines
receive no further fixes (security fixes included), and a warning annotation is added to the Job for each version.
If you cannot upgrade, the [Gradle Security Subscription](https://gradle.org/security-subscription/) offers
continued support for older versions.
- **Out of date** — one major version behind the latest release, or more than two minor versions behind on the current
major. The version is marked with :information_source: in the build results table and a notice annotation is added to
the Job. Note that a version one major behind is still in "maintenance only" support and receives critical bug fixes
and security fixes; an older minor of the current major has simply been superseded. See
[Gradle release lifecycle](https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support) for details.
Patch releases are not reported: only the major and minor version are considered. Release candidates, milestones and
snapshots are never reported, so testing against a pre-release build will not produce annotations.
Note that these annotations are always emitted, independent of the `add-job-summary` setting. Setting
`add-job-summary: 'never'` suppresses the Job Summary itself, but the warning and notice annotations remain.
### Excluding specific Gradle builds from Job Summary
The Job Summary works by installing an init-script in Gradle User Home which will record details of any Gradle execution during the workflow.
@@ -921,7 +956,7 @@ Here's a minimal example:
run:./gradlew build
```
This configuration will automatically apply `v4.4.2` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com.
This configuration will automatically apply `v4.6.0` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com.
This example assumes that the `develocity.your-server.com` server allows anonymous publishing of build scans.
In the likely scenario that your Develocity server requires authentication, you will also need to pass a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable) taken from a secret:
@@ -1005,5 +1040,19 @@ Each of the plugins is signed by Gradle, and you can simply add the following sn
@@ -111,7 +111,7 @@ we highly recommend that you reach out to us at [[email protected]](mailto:sec
#### Unverifiable Wrapper Jars
Wrapper Jars generated by Gradle versions `3.3` to `4.0` are not verifiable because those files were dynamically generated by Gradle in a non-reproducible way. It's not possible to verify the `gradle-wrapper.jar` for those versions are legitimate using a hash comparison. If you have a validation failure, you should try to determine if the `gradle-wrapper.jar` was generated by one of these versions before running the build.
- If the Gradle version in `gradle-wrapper.properties` is outside of this range, you can regenerate the `gradle-wrapper.jar` by running `./gradlew wrapper`. This will generate a new, verifiable wrapper jar.
- If the Gradle version in `gradle-wrapper.properties` is outside of this range, you can regenerate the `gradle-wrapper.jar` by running `./gradlew :wrapper`. This will generate a new, verifiable wrapper jar.
- If you need to run your build with a version of Gradle between 3.3 and 4.0, you can use a newer version of Gradle to generate the `gradle-wrapper.jar`.
'enhanced' (default) uses the full-featured commercial caching service (gradle-actions-caching).
'basic' uses a simple open-source caching implementation based on GitHub Actions cache.
'external' disables Gradle User Home caching by this action, for use when Gradle User Home is already saved and restored by another mechanism (e.g. Develocity Artifact Cache).
constENHANCED_CACHE_MESSAGE=`Enhanced Caching: This build is using the proprietary 'gradle-actions-caching' provider for optimized caching support. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for terms of use and opt-out instructions.`
constBASIC_CACHE_MESSAGE=`Basic Caching: This build uses the basic open-source caching provider. For faster builds and advanced features, consider switching to the Enhanced Caching provider. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for details.`
constEXTERNAL_CACHE_MESSAGE=`External Caching: Gradle User Home is managed by an external caching provider. This action will not restore or save Gradle User Home.`
'write-only':`[Cache was write-only](${DOCS}#using-the-cache-write-only) — Gradle User Home was not restored from the cache.`,
disabled:`[Caching was disabled](${DOCS}#disabling-caching) — Gradle User Home was not restored from or saved to the cache.`,
'disabled-existing-home':`⚠️ [Caching was skipped](${DOCS}#overwriting-an-existing-gradle-user-home) — a pre-existing Gradle User Home was found, so the cache was not restored or saved.`,
'not-available':`Caching is not available — the GitHub Actions cache service could not be reached, so Gradle User Home was not restored or saved.`
'not-available':`Caching is not available — the GitHub Actions cache service could not be reached, so Gradle User Home was not restored or saved.`,
external:`[Gradle User Home is cached externally](${DOCS}#using-an-external-cache-provider) — this action did not restore or save the Gradle User Home.`
'trial-expired':`Project state (build-logic and configuration cache) was not cached - the Develocity caching trial has expired.`,
'trial-not-licensed':`Project state (build-logic and configuration cache) was not cached - a develocity-access-key and develocity-server-url is required.`,
'no-encryption-key':`Project state (build-logic and configuration cache) was not cached - a [cache-encryption-key](${DOCS}#cache-encryption-key) is required.`,
enabled:`Caching of project state (build-logic and configuration cache) was enabled.`
}
/**
* Renders a cache report into the unified Job Summary markdown, with a consistent
* skeleton across every variant: a section heading, a status line, an integrated
@@ -55,7 +64,13 @@ function isActive(status: CacheStatus): boolean {
# Gradle start up script for POSIX generated by Gradle.
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.