Compare commits

..

99 Commits

Author SHA1 Message Date
Daz DeBoer
6c7537229b Merge pull request #1026 from gradle/dd/java-toolchains
Use Maven toolchains.xml to register pre-installed JDKs as java toolchains
2024-01-04 05:34:34 +01:00
daz
650620f9f9 Build outputs 2024-01-03 21:12:13 -07:00
daz
d4e24dfc10 Register pre-installed JDKs in .m2/toolchains.xml
Since adding these to the `org.gradle.java.installations.fromEnv` property
is problematic (#1024), this mechanism allows the default toolchains to
be discovered by Gradle via a different mechanism.

The default JDK installations are added to `~/.m2/toolchains.xml` such that
they are discoverable by Gradle toolchain support.
The `setup-java` action also writes to this file, so we merge with any existing
content: this allows both pre-installed and "setup" JDKs to be automatically
detected by Gradle.
2024-01-03 21:08:40 -07:00
daz
7c57ba1136 Remove writing value to gradle.properties in setup
The written property will override any project-level setting, which
can lead to confusing behaviour.

Fixes #1024
2024-01-03 18:49:57 -07:00
Daz DeBoer
32bab5b15a Allow entries with same Job ID to match in different workflows
Previously, the workflow name was always included when matching a cache entry for the current job.
This can be overly restrictive when job definitions are shared between different workflows. 
The workflow name is still encoded in the cache entry key, but not in the restore key searching for entries with a matching job.

Fixes #1017
2024-01-03 18:38:36 -07:00
daz
270f30ba56 Always initialize encryption key 2024-01-02 14:28:29 -07:00
daz
c00a847f3f Enable config-cache tests
- Enable in full-build
- Pass encryption key secret to test workflow
2024-01-02 11:31:06 -07:00
daz
e2aa3f332c Test with Gradle 8.6-rc-1 2024-01-01 19:29:46 -07:00
dependabot[bot]
ff5d63e9dc Bump the npm-dependencies group with 3 updates
Bumps the npm-dependencies group with 3 updates: [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser), [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) and [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier).

Updates `@typescript-eslint/parser` from 6.15.0 to 6.17.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/parser)

Updates `eslint-plugin-jest` from 27.6.0 to 27.6.1
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v27.6.0...v27.6.1)

Updates `eslint-plugin-prettier` from 5.1.1 to 5.1.2
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: eslint-plugin-prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 17:54:53 -07:00
Daz DeBoer
4faac45dc8 Merge pull request #1021 from gradle/dd/pr-comment
Automatically add Job Summary as PR comment
2024-01-02 01:51:30 +01:00
daz
45ed60450e Build outputs 2024-01-01 17:50:40 -07:00
daz
72abd931ce Set workflow permissions where required 2024-01-01 17:50:40 -07:00
daz
a4107da76d Warn when permissions not set for PR comment 2024-01-01 17:50:40 -07:00
daz
d16a3f4093 Update docs for PR comment 2024-01-01 17:50:40 -07:00
daz
333078158e Allow job-summary only on failure
Instead of a binary true/false option, it is now possible to only add
a Job Summary when the build failed. This applies both to the overall
Job Summary added to the workflow run, and to the new PR comment feature.
2024-01-01 17:50:40 -07:00
daz
34a07dced0 Automatically add Job Summary as PR comment
Rather than requiring a separate step to add a PR comment,
the `gradle-build-action` can now automatically add the Job Summary
as a PR comment

Fixes #1020
2024-01-01 17:50:15 -07:00
daz
24e9e9dc6b Refactor and simplify summary generation 2023-12-31 15:12:04 -07:00
Goooler
bc72ac9e9d Use actions/setup-java v4 in doc
https://github.com/actions/setup-java/releases/tag/v4.0.0

Signed-off-by: Goooler <wangzongler@gmail.com>
2023-12-31 21:18:55 +01:00
Daz DeBoer
c791d32284 Reference 8.6-rc-1 in docs 2023-12-31 13:17:35 -07:00
Daz DeBoer
ceb0c736c1 Document using secret for encryption key 2023-12-31 13:13:44 -07:00
Daz DeBoer
3f2ca32cb0 Document configuration-cache support 2023-12-26 18:29:50 -07:00
Daz DeBoer
5d2dd0dea4 Merge pull request #1012 from gradle/dd/artifact-lib-update
Update to actions/artifact v2.0.0
2023-12-24 05:35:16 +01:00
Daz DeBoer
e865911745 Merge pull request #1005 from gradle/dependabot/gradle/dot-github/workflow-samples/kotlin-dsl/com.google.guava-guava-33.0.0-jre
Bump com.google.guava:guava from 32.1.3-jre to 33.0.0-jre in /.github/workflow-samples/kotlin-dsl
2023-12-24 05:27:49 +01:00
daz
0538e78c32 Build outputs 2023-12-23 21:25:47 -07:00
daz
a4dabb3a70 Adapt dependency-graph support for new artifact API
- Don't upload artifacts when using 'generate-and-submit'
- New option 'generate-and-upload' to be used with 'download-and-submit'
- Use Artifact API for downloading in the same and different workflow
2023-12-23 21:24:11 -07:00
daz
51b7a82e8e Update to latest artifact lib 2023-12-23 21:23:57 -07:00
daz
92cb3fe7e8 Build outputs 2023-12-23 18:25:52 -07:00
daz
e843ea4565 Update NPM dependencies 2023-12-23 18:25:51 -07:00
dependabot[bot]
14b4921945 Bump the github-actions group with 3 updates
Bumps the github-actions group with 3 updates: [github/codeql-action](https://github.com/github/codeql-action), [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) and [actions/upload-artifact](https://github.com/actions/upload-artifact).


Updates `github/codeql-action` from 2 to 3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

Updates `gradle/gradle-build-action` from 2.10.0 to 2.11.0
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.10.0...v2.11.0)

Updates `actions/upload-artifact` from 3 to 4
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-23 18:25:51 -07:00
daz
9c7269b85b Update to latest Develocity plugins 2023-12-23 18:25:50 -07:00
Daz DeBoer
a7b743845f Merge pull request #968 : Prepare for version 3.x
Contains all functionality planned for the initial 3.x release.

- Fixes #726 
- Fixes #946 
- Fixes #966 
- Fixes #996
2023-12-23 20:43:34 +01:00
daz
e6566cde89 Build outputs 2023-12-23 12:31:17 -07:00
daz
89f8dcd819 Complete deprecation of direct Gradle execution
- Deprecate `build-root-directory` and `gradle-executable` parameters
- Remove examples from README
2023-12-23 12:22:44 -07:00
daz
93050d1483 Improvements to cache reporting
- Avoid "Entry not saved: reason unknown" when entry was not restored
- Avoid "Entry not saved: Encryption key not provided" when no config-cache data found
- Avoid spurious log message when no config-cache data found
2023-12-23 12:21:27 -07:00
daz
df38ec05e0 Use 'release-nightly' for config-cache test
Config-cache save/restore is dependent on Gradle 8.6.
Use of the release-nightly is temporary until 8.6 is released.
2023-12-23 12:21:19 -07:00
daz
b3f092e821 Avoid saving config-cache from Gradle < 8.6
Earlier versions of Gradle didn't support the `GRADLE_ENCRYPTION_KEY`
for the configuration-cache, and so are either not useful to save,
or are actually unsafe due to unencrypted secrets.

We use semver to compare the Gradle version used to produce the config-cache
entry with the minimum Gradle version required.
2023-12-23 09:13:46 -07:00
daz
63ce84df08 Don't create entry for non-existant directory
- Filter out config-cache directories that do not exist when constructing
  cache entry definitions
2023-12-23 09:12:30 -07:00
daz
57f3f23714 Improve non-restore behavior for config-cache
- Avoid logging "not restoring" message when no entries exist to restore
- Clear the entries from metadata when they are not restored. This ensures that
  the non-restored entries are correctly purged.
2023-12-23 09:08:40 -07:00
daz
38785d7d62 Update integ test for config-cache caching
- Rename test for clarity
- Use cache-encryption-key in config-cache test
2023-12-22 12:52:09 -07:00
daz
a738af78ea Provide cache-encryption-key as action input
This makes it easier for users to enable config-cache saving in their workflow.

Config-cache data will only be saved/restored when the key is provided,
and the key is exported as `GRADLE_ENCRYPTION_KEY` for use in subsequent steps.
2023-12-22 12:52:09 -07:00
daz
ae24bf6608 Log completion of post-action step 2023-12-20 19:46:02 -07:00
daz
334a4b8d4d Reinstate configuration-cache save/restore capability 2023-12-20 17:31:01 -07:00
daz
009bd36b91 Exclude cc-keystore from Gradle User Home 2023-12-20 17:31:01 -07:00
daz
9d6738618d Support wildcards in cache-excludes 2023-12-20 10:05:25 -07:00
daz
f053e6b7e7 Deprecate the arguments parameter
Fixes #996
2023-12-20 09:57:20 -07:00
daz
c821b7c4f1 Update to run on Node 20 2023-12-20 09:57:18 -07:00
daz
982da8e78c Attempt to make init-script compatible with Gradle 1.12
The `PluginManager` type wasn't introduced until Gradle 2.x.
Remove this type from the method signature in an attempt to allow this
file to be parsed with Gradle 1.12.
2023-12-19 14:12:27 -07:00
daz
a0fc8606d2 Build outputs 2023-12-19 14:08:34 -07:00
daz
a1980784de Improve reporting for dependency-graph failure
The previous message was assuming a permissions issue, and was not
including the underlying error message in the response.
2023-12-19 14:05:20 -07:00
dependabot[bot]
89e46180c6 Bump com.google.guava:guava in /.github/workflow-samples/kotlin-dsl
Bumps [com.google.guava:guava](https://github.com/google/guava) from 32.1.3-jre to 33.0.0-jre.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 22:30:59 +00:00
Daz DeBoer
f95e9c7459 Clarify dependency-graph example 2023-12-12 10:48:54 -07:00
daz
8cbcb9948b Plugin repository URL is configurable
The repository URL used to resolve the `github-dependency-graph-gradle-plugin` is now
configurable, allowing a user to specify an internal proxy if the public portal is not available.

Specify a custom plugin repository using the `GRADLE_PLUGIN_REPOSITORY_URL` env var,
or the `gradle.plugin-repository.url` System property.

Fixes #933
2023-12-11 21:15:34 -07:00
daz
a71aff6a12 Handle failure in cache-cleanup
Do not abort the remainder of the post-action on failure in cache-cleanup.
Instead, just log a warning and continue.

Fixes #858
Fixes #990
2023-12-11 20:38:28 -07:00
daz
77699bae74 Handle failure writing build-results file
Fixes #866
2023-12-11 20:18:58 -07:00
daz
dc5927259f Merge branch 'dd/dependency-updates'
* dd/dependency-updates:
  Bumps the npm-dependencies group with 5 updates:
  Bump the github-actions group with 2 updates
  Bump from Gradle 8.4 to Gradle 8.5
2023-12-11 19:49:28 -07:00
daz
4f0075d967 Clarify docs for dedicated workflow
Fixes #976
2023-12-11 19:48:32 -07:00
daz
e1f9864a52 Bumps the npm-dependencies group with 5 updates:
| Package | From | To |
    | --- | --- | --- |
    | [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) | `29.5.8` | `29.5.11` |
    | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `6.12.0` | `6.14.0` |
    | [eslint](https://github.com/eslint/eslint) | `8.54.0` | `8.55.0` |
    | [prettier](https://github.com/prettier/prettier) | `3.1.0` | `3.1.1` |
    | [typescript](https://github.com/Microsoft/TypeScript) | `5.3.2` | `5.3.3` |
2023-12-11 19:43:02 -07:00
dependabot[bot]
76d5a9b475 Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [actions/setup-java](https://github.com/actions/setup-java) and [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action).


Updates `actions/setup-java` from 3 to 4
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v3...v4)

Updates `gradle/gradle-build-action` from 2.9.0 to 2.10.0
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.9.0...v2.10.0)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 19:23:45 -07:00
daz
39d8c6d06e Bump from Gradle 8.4 to Gradle 8.5 2023-12-11 18:33:39 -07:00
Kengo TODA
0280eb7de5 docs: upload build reports even when build failed
Signed-off-by: Kengo TODA <skypencil@gmail.com>
2023-11-28 04:50:00 +01:00
daz
87a9a15658 Use 1.0.0 release of dependency graph plugin 2023-11-27 17:46:35 +10:00
Daz DeBoer
375481748b Document artifact-retention-days 2023-11-26 19:46:29 -07:00
daz
beff1c573c Update dev dependencies 2023-11-27 12:28:37 +10:00
dependabot[bot]
21a3ebb55f Bump com.fasterxml.jackson.dataformat:jackson-dataformat-smile
Bumps [com.fasterxml.jackson.dataformat:jackson-dataformat-smile](https://github.com/FasterXML/jackson-dataformats-binary) from 2.15.3 to 2.16.0.
- [Commits](https://github.com/FasterXML/jackson-dataformats-binary/compare/jackson-dataformats-binary-2.15.3...jackson-dataformats-binary-2.16.0)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-smile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-27 03:20:34 +01:00
dependabot[bot]
a5be560235 Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) and [actions/github-script](https://github.com/actions/github-script).


Updates `gradle/gradle-build-action` from 2.8.1 to 2.9.0
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.8.1...v2.9.0)

Updates `actions/github-script` from 6 to 7
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v6...v7)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/github-script
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-27 03:20:09 +01:00
Daz DeBoer
9bca466e27 Make artifact retention configurable
- Added a new `artifact-retention-days` input parameter to control retention of uploaded artifacts
- Artifacts retention will use repository settings if not overridden.
2023-11-09 00:06:31 -07:00
Daz DeBoer
f757bcfd86 Merge pull request #951 from gradle/dd/v2.9.1
Update dependencies
2023-11-09 06:19:22 +01:00
daz
8b6c211905 Bump to RC of github dependency graph plugin 2023-11-08 21:11:42 -08:00
daz
8db1c7621b Build outputs 2023-11-08 21:02:15 -08:00
daz
6eaacfc06c Update NPM dependencies 2023-11-08 21:02:15 -08:00
dependabot[bot]
750905c0ed Bump @babel/traverse from 7.21.3 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.3 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-08 21:02:15 -08:00
daz
d5fbcc8361 Bump java dependency versions in tests 2023-11-08 21:02:15 -08:00
daz
0e761ca2b4 Bump to Gradle 8.4 for tests and samples 2023-11-08 21:02:15 -08:00
daz
6b7c087721 Bump version of Develocity plugins 2023-11-08 20:35:00 -08:00
Matthew Haughton
0bfe00a136 Fix typos in README
Signed-off-by: Matthew Haughton <3flex@users.noreply.github.com>
2023-10-12 21:33:54 +02:00
Daz DeBoer
62cce3c597 FIx dependency review example in README 2023-09-30 18:24:45 -06:00
Daz DeBoer
842c587ad8 Merge pull request #911 - Improve dependency review support 2023-10-01 02:01:56 +02:00
daz
4241e05054 Document configuration for dependency-review-action 2023-09-30 17:45:44 -06:00
daz
bfa3c0508e Build outputs 2023-09-30 08:49:10 -06:00
daz
c3bdce8205 Warn on dependency-graph-submit failure
A common issue when submitting a dependency graph is that the required
'contents: write' permission is not set.
We now catch any dependency submission failure and inform the user to check
that the required permissions are available.
2023-09-30 08:47:10 -06:00
daz
f92e7c3428 Improve compat with dependency-review-action
When using 'download-and-submit' for dependency graphs, we now run the
submission immediately instead of waiting until the post-action.
This allows a single job to both submit the graph and run the dependency
review action.
2023-09-29 20:36:16 -06:00
daz
d1b726d8c1 Do not generate dependency graph in cache-cleanup
- Allow environment variables to be overridden by system properties in dependency-graph initscript
- Set `GITHUB_DEPENDENCY_GRAPH_ENABLED=false` when executing Gradle for cache cleanup
2023-09-29 22:55:54 +02:00
Daz DeBoer
6fcc109efa Dependency updates (#904)
### Github Action updates

Updates `gradle/gradle-build-action` from 2.8.0 to 2.8.1

### NPM updates

Updates `@octokit/webhooks-types` from 7.3.0 to 7.3.1
- [Release notes](https://github.com/octokit/webhooks/releases)
- [Commits](https://github.com/octokit/webhooks/compare/v7.3.0...v7.3.1)

Updates `@typescript-eslint/parser` from 6.7.2 to 6.7.3
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.3/packages/parser)

Updates `eslint` from 8.49.0 to 8.50.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.49.0...v8.50.0)
2023-09-29 13:55:35 -06:00
Benoit Pierre
fde5b4fcde fix README.md internal references
Signed-off-by: Benoit Pierre <benoit.pierre@gmail.com>
2023-09-29 21:35:43 +02:00
daz
324fbdc804 Update to dep-graph plugin 0.4.1 2023-09-29 13:22:08 -06:00
daz
5658338fb0 Build outputs 2023-09-26 15:51:30 +02:00
daz
87ccc98a2a Use correct SHA for pull request events
In a pull request, GITHUB_SHA is set to the "last merge commit on the GITHUB_REF branch".
This isn't the correct value to use when generating a dependency graph.
This changes to use the value of `pull_request.head.sha`, which is the correct
value for a dependency graph.

Fixes #882
2023-09-26 15:51:30 +02:00
daz
4441c9f9bf Update to dep-graph plugin 0.4.0 2023-09-26 15:51:30 +02:00
Daz DeBoer
b5126f31db Use github.getOctokit() for compat with GitHub Enterprise
Thanks @nise-nabe for the inspiration

Fixes #885
2023-09-21 10:55:26 -06:00
Daz DeBoer
d8615ccc8b Document configuration to publish to scans.gradle.com
Fixes #870
2023-09-21 10:47:51 -06:00
Daz DeBoer
444c20baf7 Test multiple dependency graphs on all os's 2023-09-21 18:22:31 +02:00
daz
aea76e1766 Dependency updates 2023-09-21 10:01:33 -06:00
daz
103e3a7ba7 Build outputs 2023-09-21 08:47:55 -06:00
dependabot[bot]
73e3fc21c7 Bump the npm-dependencies group with 12 updates
Bumps the npm-dependencies group with 12 updates:

| Package | From | To |
| --- | --- | --- |
| [@actions/artifact](https://github.com/actions/toolkit/tree/HEAD/packages/artifact) | `1.1.1` | `1.1.2` |
| [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) | `1.10.0` | `1.10.1` |
| [@types/unzipper](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/unzipper) | `0.10.6` | `0.10.7` |
| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `6.4.1` | `6.7.2` |
| [@vercel/ncc](https://github.com/vercel/ncc) | `0.36.1` | `0.38.0` |
| [eslint](https://github.com/eslint/eslint) | `8.47.0` | `8.49.0` |
| [eslint-plugin-github](https://github.com/github/eslint-plugin-github) | `4.9.2` | `4.10.0` |
| [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) | `27.2.3` | `27.4.0` |
| [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest) | `29.6.3` | `29.7.0` |
| [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) | `29.5.4` | `29.5.5` |
| [prettier](https://github.com/prettier/prettier) | `3.0.2` | `3.0.3` |
| [typescript](https://github.com/Microsoft/TypeScript) | `5.1.6` | `5.2.2` |


Updates `@actions/artifact` from 1.1.1 to 1.1.2
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/artifact/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/artifact)

Updates `@actions/core` from 1.10.0 to 1.10.1
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Updates `@types/unzipper` from 0.10.6 to 0.10.7
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/unzipper)

Updates `@typescript-eslint/parser` from 6.4.1 to 6.7.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.2/packages/parser)

Updates `@vercel/ncc` from 0.36.1 to 0.38.0
- [Release notes](https://github.com/vercel/ncc/releases)
- [Commits](https://github.com/vercel/ncc/compare/0.36.1...0.38.0)

Updates `eslint` from 8.47.0 to 8.49.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.47.0...v8.49.0)

Updates `eslint-plugin-github` from 4.9.2 to 4.10.0
- [Release notes](https://github.com/github/eslint-plugin-github/releases)
- [Commits](https://github.com/github/eslint-plugin-github/compare/v4.9.2...v4.10.0)

Updates `eslint-plugin-jest` from 27.2.3 to 27.4.0
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v27.2.3...v27.4.0)

Updates `jest` from 29.6.3 to 29.7.0
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v29.7.0/packages/jest)

Updates `@types/jest` from 29.5.4 to 29.5.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Updates `prettier` from 3.0.2 to 3.0.3
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.0.2...3.0.3)

Updates `typescript` from 5.1.6 to 5.2.2
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.1.6...v5.2.2)

---
updated-dependencies:
- dependency-name: "@actions/artifact"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: "@actions/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: "@types/unzipper"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: "@vercel/ncc"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: eslint-plugin-github
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-dependencies
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 08:44:23 -06:00
daz
b063df05a4 Bump GE plugin versions 2023-09-21 08:41:43 -06:00
dependabot[bot]
5e3952da92 Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action).


Updates `actions/checkout` from 3 to 4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

Updates `gradle/gradle-build-action` from 2.7.1 to 2.8.0
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.7.1...v2.8.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 16:35:57 +02:00
Daz DeBoer
ed940a329a Fix name of test dependency-graph workflow 2023-09-21 08:19:49 -06:00
Daz DeBoer
3bfe3a4658 Clarify documentation
Fixes #867
2023-09-04 16:09:52 -06:00
daz
8f08e41675 Use unique cache key for workflow 2023-08-28 12:40:55 -06:00
75 changed files with 150603 additions and 19709 deletions

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id "com.gradle.enterprise" version "3.14.1" id "com.gradle.enterprise" version "3.16.1"
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11.1" id "com.gradle.common-custom-user-data-gradle-plugin" version "1.12.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@@ -8,9 +8,9 @@ repositories {
dependencies { dependencies {
api("org.apache.commons:commons-math3:3.6.1") api("org.apache.commons:commons-math3:3.6.1")
implementation("com.google.guava:guava:32.1.2-jre") implementation("com.google.guava:guava:33.0.0-jre")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
} }
tasks.test { tasks.test {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id("com.gradle.enterprise") version "3.14.1" id("com.gradle.enterprise") version "3.16.1"
id("com.gradle.common-custom-user-data-gradle-plugin") version "1.11.1" id("com.gradle.common-custom-user-data-gradle-plugin") version "1.12.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id "com.gradle.build-scan" version "3.14.1" id "com.gradle.build-scan" version "3.16.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id "com.gradle.enterprise" version "3.14.1" id "com.gradle.enterprise" version "3.16.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -38,11 +38,11 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@@ -67,4 +67,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3

View File

@@ -15,6 +15,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v3 uses: actions/dependency-review-action@v3

View File

@@ -25,12 +25,14 @@ jobs:
cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
caching-config: caching-config:
uses: ./.github/workflows/integ-test-action-inputs-caching.yml uses: ./.github/workflows/integ-test-caching-config.yml
with: with:
cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
dependency-graph: dependency-graph:
uses: ./.github/workflows/integ-test-dependency-graph.yml uses: ./.github/workflows/integ-test-dependency-graph.yml
permissions:
contents: write
with: with:
cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
@@ -56,10 +58,12 @@ jobs:
with: with:
cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
# restore-configuration-cache: restore-configuration-cache:
# uses: ./.github/workflows/integ-test-restore-configuration-cache.yml uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
# with: with:
# cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
secrets:
GRADLE_ENCRYPTION_KEY: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
restore-custom-gradle-home: restore-custom-gradle-home:
uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml

View File

@@ -13,14 +13,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 8 java-version: 8
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2.7.1 # Use a released version to avoid breakages uses: gradle/gradle-build-action@v2.11.0 # Use a released version to avoid breakages
- name: Run integration tests - name: Run integration tests
working-directory: test/init-scripts working-directory: test/init-scripts
run: ./gradlew check run: ./gradlew check

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build and upload distribution - name: Build and upload distribution
uses: ./.github/actions/build-dist uses: ./.github/actions/build-dist
@@ -18,11 +18,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Configure Gradle as default for unit test - name: Configure Gradle as default for unit test
uses: ./ uses: ./
with: with:
gradle-version: 8.3 gradle-version: 8.5
- name: Run tests - name: Run tests
run: | run: |
npm install npm install
@@ -45,7 +45,7 @@ jobs:
caching-config: caching-config:
needs: build-distribution needs: build-distribution
uses: ./.github/workflows/integ-test-action-inputs-caching.yml uses: ./.github/workflows/integ-test-caching-config.yml
with: with:
runner-os: '["ubuntu-latest"]' runner-os: '["ubuntu-latest"]'
download-dist: true download-dist: true
@@ -53,6 +53,8 @@ jobs:
dependency-graph: dependency-graph:
needs: build-distribution needs: build-distribution
uses: ./.github/workflows/integ-test-dependency-graph.yml uses: ./.github/workflows/integ-test-dependency-graph.yml
permissions:
contents: write
with: with:
runner-os: '["ubuntu-latest"]' runner-os: '["ubuntu-latest"]'
download-dist: true download-dist: true
@@ -87,12 +89,14 @@ jobs:
runner-os: '["ubuntu-latest"]' runner-os: '["ubuntu-latest"]'
download-dist: true download-dist: true
# restore-configuration-cache: restore-configuration-cache:
# needs: build-distribution needs: build-distribution
# uses: ./.github/workflows/integ-test-restore-configuration-cache.yml uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
# with: with:
# runner-os: '["ubuntu-latest"]' runner-os: '["ubuntu-latest"]'
# download-dist: true download-dist: true
secrets:
GRADLE_ENCRYPTION_KEY: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
restore-containerized-gradle-home: restore-containerized-gradle-home:
needs: build-distribution needs: build-distribution

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build - name: Build
run: | run: |
npm -v npm -v
@@ -33,7 +33,7 @@ jobs:
id: diff id: diff
# If index.js was different than expected, upload the expected version as an artifact # If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
if: ${{ failure() && steps.diff.conclusion == 'failure' }} if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with: with:
name: dist name: dist

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Test build failure - name: Test build failure
uses: ./ uses: ./
continue-on-error: true continue-on-error: true
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Test wrapper missing - name: Test wrapper missing
uses: ./ uses: ./
continue-on-error: true continue-on-error: true
@@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Test bad config value - name: Test bad config value
uses: ./ uses: ./
continue-on-error: true continue-on-error: true

View File

@@ -8,11 +8,11 @@ env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs: jobs:
run-gradle-builds: many-gradle-builds:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build distribution - name: Build distribution
shell: bash shell: bash
run: | run: |
@@ -42,11 +42,32 @@ jobs:
continue-on-error: true continue-on-error: true
run: ./gradlew not-a-real-task run: ./gradlew not-a-real-task
successful-builds-with-no-summary:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Build distribution
shell: bash
run: |
npm install
npm run build
- name: Setup Gradle
uses: ./
with:
add-job-summary: on-failure
- name: Build kotlin-dsl project
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble
- name: Build kotlin-dsl project without Build Scan®
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble check --no-scan
pre-existing-gradle-home: pre-existing-gradle-home:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build distribution - name: Build distribution
shell: bash shell: bash
run: | run: |

View File

@@ -2,26 +2,50 @@ name: Demo adding Build Scan® comment to PR
on: on:
pull_request: pull_request:
types: [assigned, review_requested] types: [assigned, review_requested]
permissions:
pull-requests: write
jobs: jobs:
gradle: successful-build-with-always-comment:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout project sources - name: Checkout project sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with:
add-job-summary-as-pr-comment: always
- name: Run build with Gradle wrapper - name: Run build with Gradle wrapper
id: gradle id: gradle
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew build --scan run: ./gradlew build --scan
- name: "Add Build Scan URL as PR comment"
uses: actions/github-script@v6 successful-build-with-comment-on-failure:
runs-on: ubuntu-latest
steps:
- name: Checkout project sources
uses: actions/checkout@v4
- name: Setup Gradle
uses: ./
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} add-job-summary-as-pr-comment: on-failure
script: | - name: Run build with Gradle wrapper
github.rest.issues.createComment({ id: gradle
issue_number: context.issue.number, working-directory: .github/workflow-samples/kotlin-dsl
owner: context.repo.owner, run: ./gradlew build --scan
repo: context.repo.repo,
body: 'PR ready for review: ${{ steps.gradle.outputs.build-scan-url }}' failing-build-with-comment-on-failure:
}) runs-on: ubuntu-latest
steps:
- name: Checkout project sources
uses: actions/checkout@v4
- name: Setup Gradle
uses: ./
with:
add-job-summary-as-pr-comment: on-failure
- name: Run build with Gradle wrapper
id: gradle
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew no-a-real-task --scan
continue-on-error: true

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Invoke with multi-line arguments - name: Invoke with multi-line arguments

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -45,7 +45,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -65,7 +65,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -1,4 +1,4 @@
name: Test action inputs for caching name: Test caching configuration
on: on:
workflow_call: workflow_call:
@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -38,7 +38,8 @@ jobs:
enterprise enterprise
# Exclude build-cache from main cache entry # Exclude build-cache from main cache entry
gradle-home-cache-excludes: | gradle-home-cache-excludes: |
caches/build-cache-1 caches/build-cache-*
caches/*/executionHistory
- name: Build using Gradle wrapper - name: Build using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test run: ./gradlew test
@@ -52,7 +53,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -63,7 +64,8 @@ jobs:
caches caches
enterprise enterprise
gradle-home-cache-excludes: | gradle-home-cache-excludes: |
caches/build-cache-1 caches/build-cache-*
caches/*/executionHistory
cache-read-only: true cache-read-only: true
- name: Execute Gradle build with --offline - name: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
@@ -77,7 +79,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -90,7 +92,7 @@ jobs:
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}" run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check Build Scan url is captured - name: Check Build Scan url is captured
if: ${{ !steps.gradle.outputs.build-scan-url }} if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')
@@ -100,7 +102,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Create dummy Gradle User Home - name: Create dummy Gradle User Home
@@ -113,7 +115,7 @@ jobs:
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}" run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check Build Scan url is captured - name: Check Build Scan url is captured
if: ${{ !steps.gradle.outputs.build-scan-url }} if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')
@@ -128,7 +130,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -149,7 +151,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -1,4 +1,4 @@
name: Test execution with caching name: Test dependency graph
on: on:
workflow_call: workflow_call:
@@ -12,6 +12,9 @@ on:
type: boolean type: boolean
default: false default: false
permissions:
contents: write
env: env:
DOWNLOAD_DIST: ${{ inputs.download-dist }} DOWNLOAD_DIST: ${{ inputs.download-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-graph-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-graph-${{ inputs.cache-key-prefix }}
@@ -25,13 +28,13 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle for dependency-graph generate - name: Setup Gradle for dependency-graph generate
uses: ./ uses: ./
with: with:
dependency-graph: generate dependency-graph: generate-and-upload
- name: Run gradle build - name: Run gradle build
run: ./gradlew build run: ./gradlew build
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
@@ -43,7 +46,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle for dependency-graph generate - name: Setup Gradle for dependency-graph generate
@@ -55,11 +58,11 @@ jobs:
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
submit: submit:
needs: [groovy-generate, kotlin-generate] needs: [groovy-generate]
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Submit dependency graphs - name: Submit dependency graphs
@@ -68,16 +71,19 @@ jobs:
dependency-graph: download-and-submit dependency-graph: download-and-submit
multiple-builds: multiple-builds:
runs-on: "ubuntu-latest" strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle for dependency-graph generate - name: Setup Gradle for dependency-graph generate
uses: ./ uses: ./
with: with:
dependency-graph: generate dependency-graph: generate-and-submit
- id: gradle-assemble - id: gradle-assemble
run: ./gradlew assemble run: ./gradlew assemble
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
@@ -85,12 +91,16 @@ jobs:
run: ./gradlew build run: ./gradlew build
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
- name: Check generated dependency graphs - name: Check generated dependency graphs
shell: bash
run: | run: |
echo "gradle-assemble report file: ${{ steps.gradle-assemble.outputs.dependency-graph-file }}" echo "gradle-assemble report file: ${{ steps.gradle-assemble.outputs.dependency-graph-file }}"
echo "gradle-build report file: ${{ steps.gradle-build.outputs.dependency-graph-file }}" echo "gradle-build report file: ${{ steps.gradle-build.outputs.dependency-graph-file }}"
ls -l dependency-graph-reports ls -l dependency-graph-reports
if ([ ! -e ${{ steps.gradle-assemble.outputs.dependency-graph-file }} ] || [ ! -e ${{ steps.gradle-build.outputs.dependency-graph-file }} ]) if [ ! -e "${{ steps.gradle-assemble.outputs.dependency-graph-file }}" ]; then
then echo "Did not find gradle-assemble dependency graph file"
echo "Did not find expected dependency graph files" exit 1
fi
if [ ! -e "${{ steps.gradle-build.outputs.dependency-graph-file }}" ]; then
echo "Did not find gradle-build dependency graph files"
exit 1 exit 1
fi fi

View File

@@ -14,19 +14,20 @@ on:
env: env:
DOWNLOAD_DIST: ${{ inputs.download-dist }} DOWNLOAD_DIST: ${{ inputs.download-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-java-toolchain-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: detect-java-toolchain-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs: jobs:
# Test that pre-installed runner JDKs are detected # Test that pre-installed runner JDKs are detected
pre-installed-toolchains: pre-installed-toolchains:
strategy: strategy:
fail-fast: false
matrix: matrix:
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -35,7 +36,7 @@ jobs:
shell: bash shell: bash
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: | run: |
gradle -q javaToolchains > output.txt gradle --info javaToolchains > output.txt
cat output.txt cat output.txt
- name: Verify detected toolchains - name: Verify detected toolchains
shell: bash shell: bash
@@ -44,25 +45,27 @@ jobs:
grep -q 'Eclipse Temurin JDK 1.8' output.txt || (echo "::error::Did not detect preinstalled JDK 1.8" && exit 1) grep -q 'Eclipse Temurin JDK 1.8' output.txt || (echo "::error::Did not detect preinstalled JDK 1.8" && exit 1)
grep -q 'Eclipse Temurin JDK 11' output.txt || (echo "::error::Did not detect preinstalled JDK 11" && exit 1) grep -q 'Eclipse Temurin JDK 11' output.txt || (echo "::error::Did not detect preinstalled JDK 11" && exit 1)
grep -q 'Eclipse Temurin JDK 17' output.txt || (echo "::error::Did not detect preinstalled JDK 17" && exit 1) grep -q 'Eclipse Temurin JDK 17' output.txt || (echo "::error::Did not detect preinstalled JDK 17" && exit 1)
grep -q 'Eclipse Temurin JDK 21' output.txt || (echo "::error::Did not detect preinstalled JDK 21" && exit 1)
# Test that JDKs provisioned by setup-java are detected # Test that JDKs provisioned by setup-java are detected
setup-java-installed-toolchain: setup-java-installed-toolchain:
strategy: strategy:
fail-fast: false
matrix: matrix:
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java 20 - name: Setup Java 20
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '20' java-version: '20'
- name: Setup Java 16 - name: Setup Java 16
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '16' java-version: '16'
@@ -72,42 +75,19 @@ jobs:
shell: bash shell: bash
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: | run: |
gradle -q javaToolchains > output.txt gradle --info javaToolchains > output.txt
cat output.txt cat output.txt
- name: Verify detected toolchains - name: Verify setup JDKs are detected
shell: bash shell: bash
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: | run: |
grep -q 'Eclipse Temurin JDK 16' output.txt || (echo "::error::Did not detect setup-java installed JDK 16" && exit 1) grep -q 'Eclipse Temurin JDK 16' output.txt || (echo "::error::Did not detect setup-java installed JDK 16" && exit 1)
grep -q 'Eclipse Temurin JDK 20' output.txt || (echo "::error::Did not detect setup-java installed JDK 20" && exit 1) grep -q 'Eclipse Temurin JDK 20' output.txt || (echo "::error::Did not detect setup-java installed JDK 20" && exit 1)
- name: Verify pre-installed toolchains are detected
# Test that predefined JDK detection property is not overwritten by action
check-no-overwrite:
strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Configure java installations env var in Gradle User Home
shell: bash shell: bash
working-directory: .github/workflow-samples/groovy-dsl
run: | run: |
mkdir -p ~/.gradle grep -q 'Eclipse Temurin JDK 1.8' output.txt || (echo "::error::Did not detect preinstalled JDK 1.8" && exit 1)
echo "org.gradle.java.installations.fromEnv=XXXXX" > ~/.gradle/gradle.properties grep -q 'Eclipse Temurin JDK 11' output.txt || (echo "::error::Did not detect preinstalled JDK 11" && exit 1)
- name: Setup Gradle grep -q 'Eclipse Temurin JDK 17' output.txt || (echo "::error::Did not detect preinstalled JDK 17" && exit 1)
uses: ./ grep -q 'Eclipse Temurin JDK 21' output.txt || (echo "::error::Did not detect preinstalled JDK 21" && exit 1)
- name: Check gradle.properties
shell: bash
run: |
cat ~/.gradle/gradle.properties
if grep -q 'org.gradle.java.installations.fromEnv=JAVA_HOME' ~/.gradle/gradle.properties ; then
echo 'Found overwritten fromEnv'
exit 1
fi
if ! grep -q 'org.gradle.java.installations.fromEnv=XXXXX' ~/.gradle/gradle.properties ; then
echo 'Did NOT find original fromEnv'
exit 1
fi

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Execute Gradle build - name: Execute Gradle build
@@ -44,7 +44,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Execute Gradle build - name: Execute Gradle build

View File

@@ -30,7 +30,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Test use defined Gradle version - name: Test use defined Gradle version
@@ -68,11 +68,11 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 8 java-version: 8
@@ -86,7 +86,7 @@ jobs:
arguments: help -DgradleVersionCheck=${{matrix.gradle}} arguments: help -DgradleVersionCheck=${{matrix.gradle}}
- name: Check Build Scan url - name: Check Build Scan url
if: ${{ !steps.gradle.outputs.build-scan-url }} if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')

View File

@@ -21,8 +21,8 @@ env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
GRADLE_ENTERPRISE_INJECTION_ENABLED: true GRADLE_ENTERPRISE_INJECTION_ENABLED: true
GRADLE_ENTERPRISE_URL: https://ge.solutions-team.gradle.com GRADLE_ENTERPRISE_URL: https://ge.solutions-team.gradle.com
GRADLE_ENTERPRISE_PLUGIN_VERSION: 3.14.1 GRADLE_ENTERPRISE_PLUGIN_VERSION: 3.16.1
GRADLE_ENTERPRISE_CCUD_PLUGIN_VERSION: 1.11.1 GRADLE_ENTERPRISE_CCUD_PLUGIN_VERSION: 1.12.1
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
jobs: jobs:
@@ -34,11 +34,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 8 java-version: 8
@@ -54,7 +54,7 @@ jobs:
run: gradle help run: gradle help
- name: Check Build Scan url - name: Check Build Scan url
if: ${{ !steps.gradle.outputs.build-scan-url }} if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')

View File

@@ -30,7 +30,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle with v6.9 - name: Setup Gradle with v6.9
@@ -62,7 +62,7 @@ jobs:
gradle-version: current gradle-version: current
- name: Check current version output parameter - name: Check current version output parameter
if: ${{ !startsWith(steps.gradle-current.outputs.gradle-version , '8.') }} if: ${{ !startsWith(steps.gradle-current.outputs.gradle-version , '8.') }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.gradle-current.outputs.gradle-version }}"') core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.gradle-current.outputs.gradle-version }}"')
@@ -82,11 +82,11 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 8 java-version: 8
@@ -98,7 +98,7 @@ jobs:
gradle-version: ${{ matrix.gradle }} gradle-version: ${{ matrix.gradle }}
- name: Check output parameter - name: Check output parameter
if: ${{ steps.setup-gradle.outputs.gradle-version != matrix.gradle }} if: ${{ steps.setup-gradle.outputs.gradle-version != matrix.gradle }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.setup-gradle.outputs.gradle-version }}"') core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.setup-gradle.outputs.gradle-version }}"')
@@ -108,7 +108,7 @@ jobs:
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}" run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check Build Scan url - name: Check Build Scan url
if: ${{ !steps.gradle.outputs.build-scan-url }} if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')

View File

@@ -11,6 +11,9 @@ on:
download-dist: download-dist:
type: boolean type: boolean
default: false default: false
secrets:
GRADLE_ENCRYPTION_KEY:
required: true
env: env:
DOWNLOAD_DIST: ${{ inputs.download-dist }} DOWNLOAD_DIST: ${{ inputs.download-dist }}
@@ -27,16 +30,18 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with: with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches cache-read-only: false # For testing, allow writing cache entries on non-default branches
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Groovy build with configuration-cache enabled - name: Groovy build with configuration-cache enabled
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --configuration-cache run: gradle test --configuration-cache
verify-build-groovy: verify-build-groovy:
env: env:
@@ -48,19 +53,21 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with: with:
cache-read-only: true cache-read-only: true
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Groovy build with configuration-cache enabled - name: Groovy build with configuration-cache enabled
id: execute id: execute
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --configuration-cache run: gradle test --configuration-cache
- name: Check that configuration-cache was used - name: Check that configuration-cache was used
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
const fs = require('fs') const fs = require('fs')
@@ -79,7 +86,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle with no extracted cache entries restored - name: Setup Gradle with no extracted cache entries restored
@@ -88,9 +95,11 @@ jobs:
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl" GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
with: with:
cache-read-only: true cache-read-only: true
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Check execute Gradle build with configuration cache enabled (but not restored) - name: Check execute Gradle build with configuration cache enabled (but not restored)
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --configuration-cache run: gradle test --configuration-cache
seed-build-kotlin: seed-build-kotlin:
env: env:
@@ -101,16 +110,18 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with: with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches cache-read-only: false # For testing, allow writing cache entries on non-default branches
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Execute 'help' with configuration-cache enabled - name: Execute 'help' with configuration-cache enabled
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew help --configuration-cache run: gradle help --configuration-cache
modify-build-kotlin: modify-build-kotlin:
env: env:
@@ -122,16 +133,18 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with: with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches cache-read-only: false # For testing, allow writing cache entries on non-default branches
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Execute 'test' with configuration-cache enabled - name: Execute 'test' with configuration-cache enabled
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew test --configuration-cache run: gradle test --configuration-cache
# Test restore configuration-cache from the third build invocation # Test restore configuration-cache from the third build invocation
verify-build-kotlin: verify-build-kotlin:
@@ -144,19 +157,21 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
uses: ./ uses: ./
with: with:
cache-read-only: true cache-read-only: true
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-version: 8.6-rc-1
- name: Execute 'test' again with configuration-cache enabled - name: Execute 'test' again with configuration-cache enabled
id: execute id: execute
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew test --configuration-cache run: gradle test --configuration-cache
- name: Check that configuration-cache was used - name: Check that configuration-cache was used
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
const fs = require('fs') const fs = require('fs')

View File

@@ -20,11 +20,11 @@ jobs:
container: fedora:latest container: fedora:latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
java-version: 11 java-version: 11
distribution: temurin distribution: temurin
@@ -43,11 +43,11 @@ jobs:
container: fedora:latest container: fedora:latest
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
java-version: 11 java-version: 11
distribution: temurin distribution: temurin

View File

@@ -23,7 +23,7 @@ jobs:
mkdir -p $GITHUB_WORKSPACE/gradle-user-home mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -44,7 +44,7 @@ jobs:
mkdir -p $GITHUB_WORKSPACE/gradle-user-home mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -65,7 +65,7 @@ jobs:
mkdir -p $GITHUB_WORKSPACE/gradle-user-home mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -26,7 +26,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -46,7 +46,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -66,7 +66,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -86,7 +86,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle with no extracted cache entries restored - name: Setup Gradle with no extracted cache entries restored
@@ -108,7 +108,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Pre-create Gradle User Home - name: Pre-create Gradle User Home

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -45,7 +45,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -44,7 +44,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle
@@ -44,7 +44,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Download distribution if required - name: Download distribution if required
uses: ./.github/actions/download-dist uses: ./.github/actions/download-dist
- name: Setup Gradle - name: Setup Gradle

View File

@@ -1,3 +1,3 @@
# Configuration file for asdf version manager # Configuration file for asdf version manager
nodejs 16.18.1 nodejs 20.10.0
gradle 8.3 gradle 8.5

423
README.md
View File

@@ -4,24 +4,25 @@ This GitHub Action can be used to configure Gradle and optionally execute a Grad
## Why use the `gradle-build-action`? ## Why use the `gradle-build-action`?
It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v3` action provides a simple way to cache Gradle dependencies. It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v4` action provides a simple way to cache Gradle dependencies.
However, the `gradle-build-action` offers a number of advantages over this approach: However, the `gradle-build-action` offers a number of advantages over this approach:
- Easily [configure your workflow to use a specific version of Gradle](#use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached. - Easily [configure your workflow to use a specific version of Gradle](#choose-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
- More sophisticated and more efficient caching of Gradle User Home between invocations, compared to `setup-java` and most custom configurations using `actions/cache`. [More details below](#caching). - More sophisticated and more efficient caching of Gradle User Home between invocations, compared to `setup-java` and most custom configurations using `actions/cache`. [More details below](#caching-build-state-between-jobs).
- Detailed reporting of cache usage and cache configuration options allow you to [optimize the use of the GitHub actions cache](#optimizing-cache-effectiveness). - Detailed reporting of cache usage and cache configuration options allow you to [optimize the use of the GitHub actions cache](#optimizing-cache-effectiveness).
- [Generate and Submit a GitHub Dependency Graph](#github-dependency-graph-support) for your project, enabling Dependabot security alerts. - [Generate and Submit a GitHub Dependency Graph](#github-dependency-graph-support) for your project, enabling Dependabot security alerts.
- [Automatic capture of Build Scan® links](#build-scans) from the build, making these easier to locate for workflow run. - [Automatic capture of Build Scan® links](#build-reporting) from the build, making these easier to locate for workflow run.
The `gradle-build-action` is designed to provide these benefits with minimal configuration. The `gradle-build-action` is designed to provide these benefits with minimal configuration.
These features work both when Gradle is executed via the `gradle-build-action` and for any Gradle execution in subsequent steps. These features work both when Gradle is executed via the `gradle-build-action` and for any Gradle execution in subsequent steps.
## Use the action to setup Gradle ## Use the action to setup Gradle
The recommended way to use the `gradle-build-action` is in an initial "Setup Gradle" step, with subsquent steps invoking Gradle directly with a `run` step. This makes the action minimally invasive, and allows a workflow to configure and execute a Gradle execution in any way. The recommended way to use the `gradle-build-action` is in an initial "Setup Gradle" step, with subsequent steps invoking Gradle directly with a `run` step. This makes the action minimally invasive, and allows a workflow to configure and execute a Gradle execution in any way.
Most of the functionality of the `gradle-build-action` is applied via Gradle init-scripts, and so will apply to all subsequent Gradle executions on the runner, no matter how Gradle is invoked. This means that if you have an existing workflow that executes Gradle with a `run` step, you can add an initial "Setup Gradle" Step to benefit from caching, build-scan capture and other features of the gradle-build-action. The `gradle-build-action` works by configuring environment variables and by adding a set of Gradle init-scripts to the Gradle User Home. These will apply to all Gradle executions on the runner, no matter how Gradle is invoked.
This means that if you have an existing workflow that executes Gradle with a `run` step, you can add an initial "Setup Gradle" Step to benefit from caching, build-scan capture and other features of the gradle-build-action.
```yaml ```yaml
@@ -34,8 +35,8 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 11 java-version: 11
@@ -83,8 +84,8 @@ jobs:
gradle-rc: gradle-rc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
java-version: 11 java-version: 11
@@ -96,7 +97,6 @@ jobs:
- run: echo "The release-candidate version was ${{ steps.setup-gradle.outputs.gradle-version }}" - run: echo "The release-candidate version was ${{ steps.setup-gradle.outputs.gradle-version }}"
``` ```
## Caching build state between Jobs ## Caching build state between Jobs
The `gradle-build-action` will use the GitHub Actions cache to save and restore reusable state that may be speed up a subsequent build invocation. This includes most content that is downloaded from the internet as part of a build, as well as expensive to create content like compiled build scripts, transformed Jar files, etc. The `gradle-build-action` will use the GitHub Actions cache to save and restore reusable state that may be speed up a subsequent build invocation. This includes most content that is downloaded from the internet as part of a build, as well as expensive to create content like compiled build scripts, transformed Jar files, etc.
@@ -160,6 +160,31 @@ If you want override the default and have the `gradle-build-action` caches overw
cache-overwrite-existing: true cache-overwrite-existing: true
``` ```
### Saving configuration-cache data
When Gradle is executed with the [configuration-cache](https://docs.gradle.org/current/userguide/configuration_cache.html) enabled, the configuration-cache data is stored
in the project directory, at `<project-dir>/.gradle/configuration-cache`. Due to the way the configuration-cache works, [this file may contain stored credentials and other
secrets](https://docs.gradle.org/release-nightly/userguide/configuration_cache.html#config_cache:secrets), and this data needs to be encrypted in order to be safely stored in the GitHub Actions cache.
In order to benefit from configuration caching in your GitHub Actions workflow, you must:
- Execute your build with Gradle 8.6 or newer. This can be achieved directly, or via the Gradle Wrapper.
- Enable the configuration cache for your build.
- Generate a [valid Gradle encryption key](https://docs.gradle.org/8.6-rc-1/userguide/configuration_cache.html#config_cache:secrets:configuring_encryption_key) and save it as a [GitHub Actions secret](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions).
- Provide the secret key via the `cache-encryption-key` action parameter.
```yaml
jobs:
gradle-with-configuration-cache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: gradle/gradle-build-action@v3
with:
gradle-version: 8.6-rc-1
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
- run: gradle build --configuration-cache
```
### Incompatibility with other caching mechanisms ### Incompatibility with other caching mechanisms
When using `gradle-build-action` we recommend that you avoid using other mechanisms to save and restore the Gradle User Home. When using `gradle-build-action` we recommend that you avoid using other mechanisms to save and restore the Gradle User Home.
@@ -173,7 +198,7 @@ Using either of these mechanisms may interfere with the caching provided by this
### Cache debugging and analysis ### Cache debugging and analysis
A report of all cache entries restored and saved is printed to the Job Summary when saving the cache entries. A report of all cache entries restored and saved is printed to the Job Summary when saving the cache entries.
This report can provide valuable insignt into how much cache space is being used. This report can provide valuable insight into how much cache space is being used.
It is possible to enable additional debug logging for cache operations. You do via the `GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED` environment variable: It is possible to enable additional debug logging for cache operations. You do via the `GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED` environment variable:
@@ -212,7 +237,7 @@ In certain cases a particular section of Gradle User Home will be too large to m
### Cache keys ### Cache keys
The actual content of the Gradle User Home after a build is the result of many factors, including: The actual content of the Gradle User Home after a build is the result of many factors, including:
- Core Gradle build files (`settngs.gradle[.kts]`, `build.gradle[.kts]`, `gradle.properties`) - Core Gradle build files (`settings.gradle[.kts]`, `build.gradle[.kts]`, `gradle.properties`)
- Associated Gradle configuration files (`gradle-wrapper.properties`, `dependencies.toml`, etc) - Associated Gradle configuration files (`gradle-wrapper.properties`, `dependencies.toml`, etc)
- The entire content of `buildSrc` or any included builds that provide plugins. - The entire content of `buildSrc` or any included builds that provide plugins.
- The entire content of the repository, in the case of the local build cache. - The entire content of the repository, in the case of the local build cache.
@@ -234,9 +259,9 @@ This allows the most recent state to always be available in the GitHub actions c
### Finding a matching cache entry ### Finding a matching cache entry
In most cases, no exact match will exist for the cache key. Instead, the Gradle User Home will be restored for the closest matching cache entry, using a set of "restore keys". The entries will be matched with the following precedence: In most cases, no exact match will exist for the cache key. Instead, the Gradle User Home will be restored for the closest matching cache entry, using a set of "restore keys". The entries will be matched with the following precedence:
- An exact match on OS, workflow, job, matrix and Git SHA - An exact match on OS, workflow name, job id, matrix and Git SHA
- The most recent entry saved for the same OS, workflow, job and matrix values - The most recent entry saved for the same OS, workflow name, job id and matrix values
- The most recent entry saved for the same OS, workflow and job - The most recent entry saved for the same OS and job id
- The most recent entry saved for the same OS - The most recent entry saved for the same OS
Due to branch scoping of cache entries, the above match will be first performed for entries from the same branch, and then for the default ('main') branch. Due to branch scoping of cache entries, the above match will be first performed for entries from the same branch, and then for the default ('main') branch.
@@ -299,7 +324,7 @@ without writing private cache entries that could lead to evicting shared entries
If you have other long-lived development branches that would benefit from writing to the cache, If you have other long-lived development branches that would benefit from writing to the cache,
you can configure these by overriding the `cache-read-only` action parameter. you can configure these by overriding the `cache-read-only` action parameter.
See [Using the caches read-only](#using-the-caches-read-only) for more details. See [Using the cache read-only](#using-the-cache-read-only) for more details.
Similarly, you could use `cache-read-only` for certain jobs in the workflow, and instead have these jobs reuse the cache content from upstream jobs. Similarly, you could use `cache-read-only` for certain jobs in the workflow, and instead have these jobs reuse the cache content from upstream jobs.
@@ -343,62 +368,57 @@ gradle-home-cache-cleanup: true
## Build reporting ## Build reporting
The `gradle-build-action` collects information about any Gradle executions that occur in a workflow, and reports these via The `gradle-build-action` collects information about any Gradle executions that occur in a workflow, including the root project,
a Job Summary, visible in the GitHub Actions UI. For each Gradle execution, details about the invocation are listed, together with requested tasks, build outcome and any Build Scan link generated. Details of cache entries read and written are also collected.
a link to any Build Scan® published. These details are compiled into a Job Summary, which is visible in the GitHub Actions UI.
Generation of a Job Summary is enabled by default. If this is not desired, it can be disable as follows: Generation of a Job Summary is enabled by default for all Jobs using the `gradle-build-action`. This feature can be configured
so that a Job Summary is never generated, or so that a Job Summary is only generated on build failure:
```yaml ```yaml
generate-job-summary: false add-job-summary: 'on-failure' # Valid values are 'always' (default), 'never', and 'on-failure'
``` ```
Note that the action collects information about Gradle invocations via an [Initialization Script](https://docs.gradle.org/current/userguide/init_scripts.html#sec:using_an_init_script) ### Adding Job Summary as a Pull Request comment
located at `USER_HOME/.gradle/init.d/build-result-capture.init.gradle`.
If you are using init scripts for the [Gradle Enterprise Gradle Plugin](https://plugins.gradle.org/plugin/com.gradle.enterprise) like
[`scans-init.gradle` or `gradle-enterprise-init.gradle`](https://docs.gradle.com/enterprise/gradle-plugin/#scans_gradle_com),
you'll need to ensure these files are applied prior to `build-result-capture.init.gradle`.
Since Gradle applies init scripts in alphabetical order, one way to ensure this is via file naming.
### Build Scan® link as Step output It is sometimes more convenient to view the results of a GitHub Actions Job directly from the Pull Request that triggered
the Job. For this purpose you can configure the action so that Job Summary data is added as a Pull Request comment.
As well as reporting the [Build Scan](https://gradle.com/build-scans/) link in the Job Summary,
the `gradle-build-action` action makes this link available as a Step output named `build-scan-url`.
You can then use that link in subsequent actions of your workflow. For example:
```yaml ```yaml
# .github/workflows/gradle-build-pr.yml name: CI
name: Run Gradle on PRs on:
on: pull_request pull_request:
permissions:
pull-requests: write
jobs: jobs:
gradle: run-gradle-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout project sources - name: Checkout project sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v3
- name: Run build with Gradle wrapper
id: gradle
run: ./gradlew build --scan
- name: "Add Build Scan URL as PR comment"
uses: actions/github-script@v5
if: github.event_name == 'pull_request' && failure()
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} add-job-summary-as-pr-comment: on-failure # Valid values are 'never' (default), 'always', and 'on-failure'
script: | - run: ./gradlew build --scan
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ ${{ github.workflow }} failed: ${{ steps.gradle.outputs.build-scan-url }}'
})
``` ```
### Saving build outputs Note that in order to add a Pull Request comment, the workflow must be configured with the `pull-requests: write` permission.
By default, a GitHub Actions workflow using `gradle-build-action` will record the log output and any Build Scan links for your build,
but any output files generated by the build will not be saved. ### Build Scan® link as Step output
As well as reporting all [Build Scan](https://gradle.com/build-scans/) links in the Job Summary,
the `gradle-build-action` action makes this link available an an output of any Step that executes Gradle.
The output name is `build-scan-url`. You can then use the build scan link in subsequent actions of your workflow.
### Saving arbitrary build outputs
By default, a GitHub Actions workflow using `gradle-build-action` will record the log output and any Build Scan
links for your build, but any output files generated by the build will not be saved.
To save selected files from your build execution, you can use the core [Upload-Artifact](https://github.com/actions/upload-artifact) action. To save selected files from your build execution, you can use the core [Upload-Artifact](https://github.com/actions/upload-artifact) action.
For example: For example:
@@ -409,114 +429,26 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout project sources - name: Checkout project sources
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
- name: Run build with Gradle wrapper - name: Run build with Gradle wrapper
run: ./gradlew build --scan run: ./gradlew build --scan
- name: Upload build reports - name: Upload build reports
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
if: always()
with: with:
name: build-reports name: build-reports
path: build/reports/ path: build/reports/
``` ```
## Use the action to invoke Gradle ### Use of custom init-scripts in Gradle User Home
If the `gradle-build-action` is configured with an `arguments` input, then Gradle will execute a Gradle build with the arguments provided. NOTE: We recommend using the `gradle-build-action` as a "Setup Gradle" step as described above, with Gradle being invoked via a regular `run` command. Note that the action collects information about Gradle invocations via an [Initialization Script](https://docs.gradle.org/current/userguide/init_scripts.html#sec:using_an_init_script)
located at `USER_HOME/.gradle/init.d/gradle-build-action.build-result-capture.init.gradle`.
If no `arguments` are provided, the action will not execute Gradle, but will still cache Gradle state and configure build-scan capture for all subsequent Gradle executions. If you are adding any custom init scripts to the `USER_HOME/.gradle/init.d` directory, it may be necessary to ensure these files are applied prior to `gradle-build-action.build-result-capture.init.gradle`.
Since Gradle applies init scripts in alphabetical order, one way to ensure this is via file naming.
```yaml
name: Run Gradle on PRs
on: pull_request
jobs:
gradle:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 11
- name: Setup and execute Gradle 'test' task
uses: gradle/gradle-build-action@v2
with:
arguments: test
```
### Multiple Gradle executions in the same Job
It is possible to configure multiple Gradle executions to run sequentially in the same job.
The initial Action step will perform the Gradle setup.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: assemble
- uses: gradle/gradle-build-action@v2
with:
arguments: check
```
### Gradle command-line arguments
The `arguments` input can be used to pass arbitrary arguments to the `gradle` command line.
Arguments can be supplied in a single line, or as a multi-line input.
Here are some valid examples:
```yaml
arguments: build
arguments: check --scan
arguments: some arbitrary tasks
arguments: build -PgradleProperty=foo
arguments: |
build
--scan
-PgradleProperty=foo
-DsystemProperty=bar
```
If you need to pass environment variables, use the GitHub Actions workflow syntax:
```yaml
- uses: gradle/gradle-build-action@v2
env:
CI: true
with:
arguments: build
```
### Gradle build located in a subdirectory
By default, the action will execute Gradle in the root directory of your project.
Use the `build-root-directory` input to target a Gradle build in a subdirectory.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: build
build-root-directory: some/subdirectory
```
### Using a specific Gradle executable
The action will first look for a Gradle wrapper script in the root directory of your project.
If not found, `gradle` will be executed from the PATH.
Use the `gradle-executable` input to execute using a specific Gradle installation.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: build
gradle-executable: /path/to/installed/gradle
```
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
## Support for GitHub Enterprise Server (GHES) ## Support for GitHub Enterprise Server (GHES)
@@ -532,7 +464,7 @@ The `gradle-build-action` has support for submitting a [GitHub Dependency Graph]
The dependency graph snapshot is generated via integration with the [GitHub Dependency Graph Gradle Plugin](https://plugins.gradle.org/plugin/org.gradle.github-dependency-graph-gradle-plugin), and saved as a workflow artifact. The generated snapshot files can be submitted either in the same job, or in a subsequent job (in the same or a dependent workflow). The dependency graph snapshot is generated via integration with the [GitHub Dependency Graph Gradle Plugin](https://plugins.gradle.org/plugin/org.gradle.github-dependency-graph-gradle-plugin), and saved as a workflow artifact. The generated snapshot files can be submitted either in the same job, or in a subsequent job (in the same or a dependent workflow).
The generated dependency graph snapshot reports all of the dependencies that were resolved during a bulid execution, and is used by GitHub to generate [Dependabot Alerts](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) for vulnerable dependencies, as well as to populate the [Dependency Graph insights view](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository#viewing-the-dependency-graph). The generated dependency graph snapshot reports all of the dependencies that were resolved during a build execution, and is used by GitHub to generate [Dependabot Alerts](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) for vulnerable dependencies, as well as to populate the [Dependency Graph insights view](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository#viewing-the-dependency-graph).
## Enable Dependency Graph generation for a workflow ## Enable Dependency Graph generation for a workflow
@@ -545,11 +477,9 @@ You enable GitHub Dependency Graph support by setting the `dependency-graph` act
| `generate-and-submit` | As per `generate`, but any generated dependency graph snapshots will be submitted at the end of the job. | | `generate-and-submit` | As per `generate`, but any generated dependency graph snapshots will be submitted at the end of the job. |
| `download-and-submit` | Download any previously saved dependency graph snapshots, submitting them via the Dependency Submission API. This can be useful to collect all snapshots in a matrix of builds and submit them in one step. | | `download-and-submit` | Download any previously saved dependency graph snapshots, submitting them via the Dependency Submission API. This can be useful to collect all snapshots in a matrix of builds and submit them in one step. |
Dependency Graph _submission_ (but not generation) requires the `contents: write` permission, which may need to be explicitly enabled in the workflow file. Example of a CI workflow that generates and submits a dependency graph:
Example of a simple workflow that generates and submits a dependency graph:
```yaml ```yaml
name: Submit dependency graph name: CI build
on: on:
push: push:
@@ -560,19 +490,89 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs - name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
dependency-graph: generate-and-submit dependency-graph: generate-and-submit
- name: Run a build, generating the dependency graph snapshot which will be submitted - name: Run the usual CI build (dependency-graph will be generated and submitted post-job)
run: ./gradlew build run: ./gradlew build
``` ```
The `contents: write` permission is not required to generate the dependency graph, but is required in order to submit the graph via the GitHub API. The `contents: write` permission is required in order to submit (but not generate) the dependency graph file.
Depending on [repository settings](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token), this permission may be available by default or may need to be explicitly enabled in the workflow file (as above).
The above configuration will work for workflows that run as a result of commits to a repository branch, but not when a workflow is triggered by a PR from a repository fork. > [!IMPORTANT]
For a configuration that supports this setup, see [Dependency Graphs for pull request workflows](#dependency-graphs-for-pull-request-workflows). > The above configuration will work for workflows that run as a result of commits to a repository branch,
> but not when a workflow is triggered by a PR from a repository fork.
> This is because the `contents: write` permission is not available when executing a workflow
> for a PR submitted from a forked repository.
> For a configuration that supports this setup, see [Dependency Graphs for pull request workflows](#dependency-graphs-for-pull-request-workflows).
### Using a custom plugin repository
By default, the action downloads the `github-dependency-graph-gradle-plugin` from the Gradle Plugin Portal (https://plugins.gradle.org). If your GitHub Actions environment does not have access to this URL, you can specify a custom plugin repository to use.
Do so by setting the `GRADLE_PLUGIN_REPOSITORY_URL` environment variable with your Gradle invocation.
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2
with:
dependency-graph: generate-and-submit
- name: Run a build, resolving the 'dependency-graph' plugin from the plugin portal proxy
run: ./gradlew build
env:
GRADLE_PLUGIN_REPOSITORY_URL: "https://gradle-plugins-proxy.mycorp.com"
```
### Integrating the `dependency-review-action`
The GitHub [dependency-review-action](https://github.com/actions/dependency-review-action) helps you
understand dependency changes (and the security impact of these changes) for a pull request.
For the `dependency-review-action` to succeed, it must run _after_ the dependency graph has been submitted for a PR.
When using `generate-and-submit`, dependency graph files are submitted at the end of the job, after all steps have been
executed. For this reason, the `dependency-review-action` must be executed in a dependent job,
and not as a subsequent step in the job that generates the dependency graph.
Example of a pull request workflow that executes a build for a pull request and runs the `dependency-review-action`:
```yaml
name: PR check
on:
pull_request:
permissions:
contents: write
# Note that this permission will not be available if the PR is from a forked repository
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2
with:
dependency-graph: generate-and-submit
- name: Run a build and generate the dependency graph which will be submitted post-job
run: ./gradlew build
dependency-review:
needs: build
runs-on: ubuntu-latest
- name: Perform dependency review
uses: actions/dependency-review-action@v3
```
See [Dependency Graphs for pull request workflows](#dependency-graphs-for-pull-request-workflows) for a more complex
(and less functional) example that will work for pull requests submitted from forked repositories.
## Limiting the scope of the dependency graph ## Limiting the scope of the dependency graph
@@ -582,7 +582,7 @@ For example, a vulnerability in the tool you use to generate documentation is un
There are a number of techniques you can employ to limit the scope of the generated dependency graph: There are a number of techniques you can employ to limit the scope of the generated dependency graph:
- [Don't generate a dependency graph for all Gradle executions](#choosing-which-gradle-invocations-will-generate-a-dependency-graph) - [Don't generate a dependency graph for all Gradle executions](#choosing-which-gradle-invocations-will-generate-a-dependency-graph)
- [For a Gradle execution, filter which Gradle projects and configurations will contribute dependencies](#filtering-which-gradle-configurations-contribute-to-the-dependency-graph) - [For a Gradle execution, filter which Gradle projects and configurations will contribute dependencies](#filtering-which-gradle-configurations-contribute-to-the-dependency-graph)
- [Use a separate workflow that only resolves the required dependencies]() - [Use a separate workflow that only resolves the required dependencies](#use-a-dedicated-workflow-for-dependency-graph-generation)
> [!NOTE] > [!NOTE]
> Ideally, all dependencies involved in building and testing a project will be extracted and reported in a dependency graph. > Ideally, all dependencies involved in building and testing a project will be extracted and reported in a dependency graph.
@@ -599,7 +599,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs - name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
@@ -631,12 +631,12 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs - name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
dependency-graph: generate-and-submit dependency-graph: generate-and-submit
- name: Run a build, generating the dependency graph from 'runtimeClasspath' configurations - name: Run a build, generating the dependency graph from any resolved 'runtimeClasspath' configurations
run: ./gradlew build run: ./gradlew build
env: env:
DEPENDENCY_GRAPH_INCLUDE_PROJECTS: "^:(?!buildSrc).*" DEPENDENCY_GRAPH_INCLUDE_PROJECTS: "^:(?!buildSrc).*"
@@ -645,26 +645,27 @@ jobs:
### Use a dedicated workflow for dependency graph generation ### Use a dedicated workflow for dependency graph generation
Instead of generating a dependency graph from your existing CI workflow, it's possible to create a separate dedicated workflow (or Job) that is solely intended for generating a dependency graph. Instead of generating a dependency graph from your existing CI workflow, it's possible to create a separate dedicated workflow (or Job) that is intended for generating a dependency graph.
Such a workflow will still need to execute Gradle, but can do so in a way that is targeted at resolving exactly the dependencies required. Such a workflow will still need to execute Gradle, but can do so in a way that is targeted at resolving the specific dependencies required.
For example, the following workflow will report only those dependencies that are part of the `runtimeClasspath` or the `my-app` project. For example, the following workflow will report those dependencies that are resolved in order to build the `distributionZip` for the `my-app` project. Test dependencies and other dependencies not required by the `distributionZip` will not be included.
```yaml ```yaml
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs - name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
dependency-graph: generate-and-submit dependency-graph: generate-and-submit
- name: Extract the 'runtimeClasspath' dependencies for 'my-app' - name: Build the distribution Zip for `my-app`
run: ./gradlew :my-app:dependencies --configuration runtimeClasspath run: ./gradlew :my-app:distributionZip
``` ```
Note that the above example will also include `buildSrc` dependencies, since these are resolved as part of running the `dependencies` task. Note that the above example will also include any `buildSrc` dependencies, dependencies resolved when configuring your Gradle build or dependencies resolved while applying plugin. All of these dependencies are resolved in the process of running the `distributionZip` task, and thus will form part of the generated dependency graph.
If this isn't desirable, you will still need to use the filtering mechanism described above. If this isn't desirable, you will still need to use the filtering mechanism described above.
## Dependency Graphs for pull request workflows ## Dependency Graphs for pull request workflows
@@ -681,11 +682,14 @@ Note: when `download-and-submit` is used in a workflow triggered via [workflow_r
```yaml ```yaml
name: run-build-and-generate-dependency-snapshot name: run-build-and-generate-dependency-snapshot
on:
pull_request:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle to generate and submit dependency graphs - name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
@@ -704,15 +708,48 @@ on:
types: [completed] types: [completed]
jobs: jobs:
submit-snapshots: submit-dependency-graph:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Retrieve dependency graph artifact and submit - name: Retrieve dependency graph artifact and submit
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
with: with:
dependency-graph: download-and-submit dependency-graph: download-and-submit
``` ```
### Integrating `dependency-review-action` for pull request workflows
The GitHub [dependency-review-action](https://github.com/actions/dependency-review-action) helps you
understand dependency changes (and the security impact of these changes) for a pull request.
To integrate the `dependency-review-action` into the pull request workflows above, a separate workflow should be added.
This workflow will be triggered directly on `pull_request`, but will need to wait until the dependency graph results are
submitted before the dependency review can complete. How long to wait is controlled by the `retry-on-snapshot-warnings` input parameters.
Here's an example of a separate "Dependency Review" workflow that will wait for 10 minutes for the PR check workflow to complete.
```yaml
name: dependency-review
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Dependency Review'
uses: actions/dependency-review-action@v3
with:
retry-on-snapshot-warnings: true
retry-on-snapshot-warnings-timeout: 600
```
The `retry-on-snapshot-warnings-timeout` (in seconds) needs to be long enough to allow the entire `run-build-and-generate-dependency-snapshot` and `submit-dependency-snapshot` workflows (above) to complete.
## Gradle version compatibility ## Gradle version compatibility
The GitHub Dependency Graph plugin should be compatible with all versions of Gradle >= 5.0, and has been tested against The GitHub Dependency Graph plugin should be compatible with all versions of Gradle >= 5.0, and has been tested against
@@ -726,6 +763,23 @@ limited to Gradle "8.1.0" and later:
To use this plugin with versions of Gradle older than "8.1.0", you'll need to invoke Gradle with the To use this plugin with versions of Gradle older than "8.1.0", you'll need to invoke Gradle with the
configuration-cache disabled. configuration-cache disabled.
## Reducing storage costs for saved dependency graph artifacts
When `generate` or `generate-and-submit` is used with the action, the dependency graph that is generated is stored as a workflow artifact.
By default, these artifacts are retained for a period of 30 days (or as configured for the repository).
To reduce storage costs for these artifacts, you can set the `artifact-retention-days` value to a lower number.
```yaml
steps:
- name: Generate dependency graph, but only retain artifact for one day
uses: gradle/gradle-build-action@v2
with:
dependency-graph: generate
artifact-retention-days: 1
```
# Gradle Enterprise plugin injection # Gradle Enterprise plugin injection
The `gradle-build-action` provides support for injecting and configuring the Gradle Enterprise Gradle plugin into any Gradle build, without any modification to the project sources. The `gradle-build-action` provides support for injecting and configuring the Gradle Enterprise Gradle plugin into any Gradle build, without any modification to the project sources.
@@ -745,21 +799,21 @@ name: Run build with Gradle Enterprise injection
env: env:
GRADLE_ENTERPRISE_INJECTION_ENABLED: true GRADLE_ENTERPRISE_INJECTION_ENABLED: true
GRADLE_ENTERPRISE_URL: https://ge.gradle.org GRADLE_ENTERPRISE_URL: https://ge.gradle.org
GRADLE_ENTERPRISE_PLUGIN_VERSION: 3.14.1 GRADLE_ENTERPRISE_PLUGIN_VERSION: 3.16.1
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GE_ACCESS_KEY }} # Required to publish scans to ge.gradle.org GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GE_ACCESS_KEY }} # Required to publish scans to ge.gradle.org
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
- name: Run a Gradle build with Gradle Enterprise injection enabled - name: Run a Gradle build with Gradle Enterprise injection enabled
run: ./gradlew build run: ./gradlew build
``` ```
This configuration will automatically apply `v3.14.1` of the [Gradle Enterprise Gradle plugin](https://docs.gradle.com/enterprise/gradle-plugin/), and publish build scans to https://ge.gradle.org. This configuration will automatically apply `v3.16.1` of the [Gradle Enterprise Gradle plugin](https://docs.gradle.com/enterprise/gradle-plugin/), and publish build scans to https://ge.gradle.org.
Note that the `ge.gradle.org` server requires authentication in order to publish scans. The provided `GRADLE_ENTERPRISE_ACCESS_KEY` isn't required by the Gradle Enterprise injection script, Note that the `ge.gradle.org` server requires authentication in order to publish scans. The provided `GRADLE_ENTERPRISE_ACCESS_KEY` isn't required by the Gradle Enterprise injection script,
but will be used by the GE plugin in order to authenticate with the server. but will be used by the GE plugin in order to authenticate with the server.
@@ -777,3 +831,14 @@ The `init-script` supports a number of additional configuration parameters that
| GRADLE_ENTERPRISE_PLUGIN_VERSION | :white_check_mark: | the version of the [Gradle Enterprise Gradle plugin](https://docs.gradle.com/enterprise/gradle-plugin/) to apply | | GRADLE_ENTERPRISE_PLUGIN_VERSION | :white_check_mark: | the version of the [Gradle Enterprise Gradle plugin](https://docs.gradle.com/enterprise/gradle-plugin/) to apply |
| GRADLE_ENTERPRISE_CCUD_PLUGIN_VERSION | | the version of the [Common Custom User Data Gradle plugin](https://github.com/gradle/common-custom-user-data-gradle-plugin) to apply, if any | | GRADLE_ENTERPRISE_CCUD_PLUGIN_VERSION | | the version of the [Common Custom User Data Gradle plugin](https://github.com/gradle/common-custom-user-data-gradle-plugin) to apply, if any |
| GRADLE_ENTERPRISE_PLUGIN_REPOSITORY_URL | | the URL of the repository to use when resolving the GE and CCUD plugins; the Gradle Plugin Portal is used by default | | GRADLE_ENTERPRISE_PLUGIN_REPOSITORY_URL | | the URL of the repository to use when resolving the GE and CCUD plugins; the Gradle Plugin Portal is used by default |
## Publishing to scans.gradle.com
Gradle Enterprise injection is designed to enable publishing of build scans to a Gradle Enterprise instance,
and is not suitable for publishing to the public Build Scans instance (https://scans.gradle.com).
In order to publish Build Scans to scans.gradle.com, you need to:
- Apply the Gradle Enterprise plugin to your build configuration ([see docs](https://docs.gradle.com/enterprise/get-started/#applying_the_plugin))
- Programmatically accept the Terms of Service for scans.gradle.com ([see docs](https://docs.gradle.com/enterprise/gradle-plugin/#connecting_to_scans_gradle_com))
- Execute the build with `--scan` or configure your build with `publishAlways()` ([see docs](https://docs.gradle.com/enterprise/get-started/#always_publishing_a_build_scan))

View File

@@ -8,14 +8,6 @@ inputs:
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle. description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
required: false required: false
gradle-executable:
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
required: false
build-root-directory:
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
required: false
cache-disabled: cache-disabled:
description: When 'true', all caching is disabled. No entries will be written to or read from the cache. description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
required: false required: false
@@ -40,6 +32,13 @@ inputs:
required: false required: false
default: false default: false
cache-encryption-key:
description: |
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A suitable key can be generated with `openssl rand -base64 16`.
Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false
gradle-home-cache-includes: gradle-home-cache-includes:
description: Paths within Gradle User Home to cache. description: Paths within Gradle User Home to cache.
required: false required: false
@@ -54,19 +53,51 @@ inputs:
# gradle-home-cache-excludes: | # gradle-home-cache-excludes: |
# caches/build-cache-1 # caches/build-cache-1
gradle-home-cache-cleanup:
description: When 'true', the action will attempt to remove any stale/unused entries from the Gradle User Home prior to saving to the GitHub Actions cache.
required: false
default: false
add-job-summary:
description: Specifies when a Job Summary should be inluded in the action results. Valid values are 'never', 'always' (default), and 'on-failure'.
required: false
default: 'always'
add-job-summary-as-pr-comment:
description: Specifies when each Job Summary should be added as a PR comment. Valid values are 'never' (default), 'always', and 'on-failure'. No action will be taken if the workflow was not triggered from a pull request.
required: false
default: 'never'
dependency-graph:
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit', 'generate-and-upload' and 'download-and-submit'.
required: false
default: 'disabled'
artifact-retention-days:
description: Specifies the number of days to retain any artifacts generated by the action. If not set, the default retention settings for the repository will apply.
required: false
# DEPRECATED ACTION INPUTS
arguments: arguments:
description: Gradle command line arguments (supports multi-line input) description: Gradle command line arguments (supports multi-line input)
required: false required: false
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
build-root-directory:
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
required: false
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
gradle-executable:
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
required: false
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
generate-job-summary: generate-job-summary:
description: When 'false', no Job Summary will be generated for the Job. description: When 'false', no Job Summary will be generated for the Job.
required: false required: false
default: true default: true
deprecation-message: Superceded by the new 'add-job-summary' and 'add-job-summary-as-pr-comment' parameters.
dependency-graph:
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit' and 'download-and-submit'.
required: false
default: 'disabled'
# EXPERIMENTAL & INTERNAL ACTION INPUTS # EXPERIMENTAL & INTERNAL ACTION INPUTS
# The following action properties allow fine-grained tweaking of the action caching behaviour. # The following action properties allow fine-grained tweaking of the action caching behaviour.
@@ -76,14 +107,11 @@ inputs:
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs. description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
required: false required: false
default: false default: false
workflow-job-context: workflow-job-context:
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL). description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
required: false required: false
default: ${{ toJSON(matrix) }} default: ${{ toJSON(matrix) }}
gradle-home-cache-cleanup:
description: When 'true', the action will attempt to remove any stale/unused entries from the Gradle User Home prior to saving to the GitHub Actions cache.
required: false
default: false
github-token: github-token:
description: The GitHub token used to authenticate when submitting via the Dependency Submission API. description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
@@ -99,7 +127,7 @@ outputs:
description: Version of Gradle that was setup by the action description: Version of Gradle that was setup by the action
runs: runs:
using: 'node16' using: 'node20'
main: 'dist/main/index.js' main: 'dist/main/index.js'
post: 'dist/post/index.js' post: 'dist/post/index.js'

82167
dist/main/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

81322
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4870
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,11 +8,9 @@
"format": "prettier --write **/*.ts", "format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts", "format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts", "lint": "eslint src/**/*.ts",
"compile-main": "ncc build src/main.ts --out dist/main --source-map --no-source-map-register", "compile-main": "ncc build src/main.ts --out dist/main --source-map --no-source-map-register",
"compile-post": "ncc build src/post.ts --out dist/post --source-map --no-source-map-register", "compile-post": "ncc build src/post.ts --out dist/post --source-map --no-source-map-register",
"compile": "npm run compile-main && npm run compile-post", "compile": "npm run compile-main && npm run compile-post",
"test": "jest", "test": "jest",
"check": "npm run format && npm run lint", "check": "npm run format && npm run lint",
"build": "npm run check && npm run compile", "build": "npm run check && npm run compile",
@@ -30,32 +28,34 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/artifact": "1.1.1", "@actions/artifact": "2.0.0",
"@actions/cache": "3.2.2", "@actions/cache": "3.2.2",
"@actions/core": "1.10.0", "@actions/core": "1.10.1",
"@actions/exec": "1.1.1", "@actions/exec": "1.1.1",
"@actions/github": "5.1.1", "@actions/github": "6.0.0",
"@actions/glob": "0.4.0", "@actions/glob": "0.4.0",
"@actions/http-client": "2.1.1", "@actions/http-client": "2.2.0",
"@actions/tool-cache": "2.0.1", "@actions/tool-cache": "2.0.1",
"@octokit/rest": "19.0.13", "@octokit/rest": "19.0.13",
"@octokit/webhooks-types": "7.3.1",
"semver": "7.5.4",
"string-argv": "0.3.2" "string-argv": "0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "16.18.38", "@types/jest": "29.5.11",
"@types/jest": "29.5.4", "@types/node": "20.10.0",
"@types/unzipper": "0.10.6", "@types/unzipper": "0.10.9",
"@typescript-eslint/parser": "6.4.1", "@typescript-eslint/parser": "6.17.0",
"@vercel/ncc": "0.36.1", "@vercel/ncc": "0.38.1",
"eslint": "8.47.0", "eslint": "8.56.0",
"eslint-plugin-github": "4.9.2", "eslint-plugin-github": "4.10.1",
"eslint-plugin-jest": "27.2.3", "eslint-plugin-jest": "27.6.1",
"eslint-plugin-prettier": "5.0.0", "eslint-plugin-prettier": "5.1.2",
"jest": "29.6.3", "jest": "29.7.0",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"patch-package": "8.0.0", "patch-package": "8.0.0",
"prettier": "3.0.2", "prettier": "3.1.1",
"ts-jest": "29.1.1", "ts-jest": "29.1.1",
"typescript": "5.1.6" "typescript": "5.3.3"
} }
} }

View File

@@ -1,11 +1,13 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as exec from '@actions/exec' import * as exec from '@actions/exec'
import * as glob from '@actions/glob'
import path from 'path' import path from 'path'
import fs from 'fs' import fs from 'fs'
import * as params from './input-params' import * as params from './input-params'
import {CacheListener} from './cache-reporting' import {CacheListener} from './cache-reporting'
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils' import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
import {GradleHomeEntryExtractor} from './cache-extract-entries' import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './cache-extract-entries'
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key' const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
@@ -15,22 +17,24 @@ export class GradleStateCache {
private cacheName: string private cacheName: string
private cacheDescription: string private cacheDescription: string
protected readonly userHome: string
protected readonly gradleUserHome: string protected readonly gradleUserHome: string
constructor(gradleUserHome: string) { constructor(userHome: string, gradleUserHome: string) {
this.userHome = userHome
this.gradleUserHome = gradleUserHome this.gradleUserHome = gradleUserHome
this.cacheName = 'gradle' this.cacheName = 'gradle'
this.cacheDescription = 'Gradle User Home' this.cacheDescription = 'Gradle User Home'
} }
init(): void { init(): void {
const actionCacheDir = path.resolve(this.gradleUserHome, '.gradle-build-action') this.initializeGradleUserHome()
fs.mkdirSync(actionCacheDir, {recursive: true})
const initScriptsDir = path.resolve(this.gradleUserHome, 'init.d') // Export the GRADLE_ENCRYPTION_KEY variable if provided
fs.mkdirSync(initScriptsDir, {recursive: true}) const encryptionKey = params.getCacheEncryptionKey()
if (encryptionKey) {
this.initializeGradleUserHome(this.gradleUserHome, initScriptsDir) core.exportVariable('GRADLE_ENCRYPTION_KEY', encryptionKey)
}
} }
cacheOutputExists(): boolean { cacheOutputExists(): boolean {
@@ -79,7 +83,7 @@ export class GradleStateCache {
async afterRestore(listener: CacheListener): Promise<void> { async afterRestore(listener: CacheListener): Promise<void> {
await this.debugReportGradleUserHomeSize('as restored from cache') await this.debugReportGradleUserHomeSize('as restored from cache')
await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener) await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener)
// await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener) await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
await this.debugReportGradleUserHomeSize('after restoring common artifacts') await this.debugReportGradleUserHomeSize('after restoring common artifacts')
} }
@@ -127,10 +131,10 @@ export class GradleStateCache {
*/ */
async beforeSave(listener: CacheListener): Promise<void> { async beforeSave(listener: CacheListener): Promise<void> {
await this.debugReportGradleUserHomeSize('before saving common artifacts') await this.debugReportGradleUserHomeSize('before saving common artifacts')
this.deleteExcludedPaths() await this.deleteExcludedPaths()
await Promise.all([ await Promise.all([
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener) new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener),
// new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener) new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
]) ])
await this.debugReportGradleUserHomeSize( await this.debugReportGradleUserHomeSize(
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)" "after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
@@ -140,13 +144,21 @@ export class GradleStateCache {
/** /**
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter. * Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
*/ */
private deleteExcludedPaths(): void { private async deleteExcludedPaths(): Promise<void> {
const rawPaths: string[] = params.getCacheExcludes() const rawPaths: string[] = params.getCacheExcludes()
rawPaths.push('caches/*/cc-keystore')
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x)) const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
for (const p of resolvedPaths) { for (const p of resolvedPaths) {
cacheDebug(`Deleting excluded path: ${p}`) cacheDebug(`Removing excluded path: ${p}`)
tryDelete(p) const globber = await glob.create(p, {
implicitDescendants: false
})
for (const toDelete of await globber.glob()) {
cacheDebug(`Removing excluded file: ${toDelete}`)
await tryDelete(toDelete)
}
} }
} }
@@ -171,23 +183,21 @@ export class GradleStateCache {
return path.resolve(this.gradleUserHome, rawPath) return path.resolve(this.gradleUserHome, rawPath)
} }
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void { private initializeGradleUserHome(): void {
// Ensure that pre-installed java versions are detected. Only add property if it isn't already defined. // Create a directory for storing action metadata
const gradleProperties = path.resolve(gradleUserHome, 'gradle.properties') const actionCacheDir = path.resolve(this.gradleUserHome, '.gradle-build-action')
const existingGradleProperties = fs.existsSync(gradleProperties) fs.mkdirSync(actionCacheDir, {recursive: true})
? fs.readFileSync(gradleProperties, 'utf8')
: ''
if (!existingGradleProperties.includes('org.gradle.java.installations.fromEnv=')) {
fs.appendFileSync(
gradleProperties,
`
# Auto-detect pre-installed JDKs
org.gradle.java.installations.fromEnv=JAVA_HOME_8_X64,JAVA_HOME_11_X64,JAVA_HOME_17_X64
`
)
}
// Copy init scripts from src/resources this.copyInitScripts()
// Copy the default toolchain definitions to `~/.m2/toolchains.xml`
this.registerToolchains()
}
private copyInitScripts(): void {
// Copy init scripts from src/resources to Gradle UserHome
const initScriptsDir = path.resolve(this.gradleUserHome, 'init.d')
fs.mkdirSync(initScriptsDir, {recursive: true})
const initScriptFilenames = [ const initScriptFilenames = [
'gradle-build-action.build-result-capture.init.gradle', 'gradle-build-action.build-result-capture.init.gradle',
'gradle-build-action.build-result-capture-service.plugin.groovy', 'gradle-build-action.build-result-capture-service.plugin.groovy',
@@ -196,15 +206,36 @@ org.gradle.java.installations.fromEnv=JAVA_HOME_8_X64,JAVA_HOME_11_X64,JAVA_HOME
'gradle-build-action.inject-gradle-enterprise.init.gradle' 'gradle-build-action.inject-gradle-enterprise.init.gradle'
] ]
for (const initScriptFilename of initScriptFilenames) { for (const initScriptFilename of initScriptFilenames) {
const initScriptContent = this.readInitScriptAsString(initScriptFilename) const initScriptContent = this.readResourceFileAsString('init-scripts', initScriptFilename)
const initScriptPath = path.resolve(initScriptsDir, initScriptFilename) const initScriptPath = path.resolve(initScriptsDir, initScriptFilename)
fs.writeFileSync(initScriptPath, initScriptContent) fs.writeFileSync(initScriptPath, initScriptContent)
} }
} }
private readInitScriptAsString(resource: string): string { private registerToolchains(): void {
const preInstalledToolchains = this.readResourceFileAsString('toolchains.xml')
const m2dir = path.resolve(this.userHome, '.m2')
const toolchainXmlTarget = path.resolve(m2dir, 'toolchains.xml')
if (!fs.existsSync(toolchainXmlTarget)) {
// Write a new toolchains.xml file if it doesn't exist
fs.mkdirSync(m2dir, {recursive: true})
fs.writeFileSync(toolchainXmlTarget, preInstalledToolchains)
core.info(`Wrote default JDK locations to ${toolchainXmlTarget}`)
} else {
// Merge into an existing toolchains.xml file
const existingToolchainContent = fs.readFileSync(toolchainXmlTarget, 'utf8')
const appendedContent = preInstalledToolchains.split('<toolchains>').pop()!
const mergedContent = existingToolchainContent.replace('</toolchains>', appendedContent)
fs.writeFileSync(toolchainXmlTarget, mergedContent)
core.info(`Merged default JDK locations into ${toolchainXmlTarget}`)
}
}
private readResourceFileAsString(...paths: string[]): string {
// Resolving relative to __dirname will allow node to find the resource at runtime // Resolving relative to __dirname will allow node to find the resource at runtime
const absolutePath = path.resolve(__dirname, '..', '..', 'src', 'resources', 'init-scripts', resource) const absolutePath = path.resolve(__dirname, '..', '..', 'src', 'resources', ...paths)
return fs.readFileSync(absolutePath, 'utf8') return fs.readFileSync(absolutePath, 'utf8')
} }

View File

@@ -42,7 +42,8 @@ export class CacheCleaner {
) )
fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}') fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}')
await exec.exec(`gradle -g ${this.gradleUserHome} --no-daemon --build-cache --no-scan --quiet noop`, [], { const gradleCommand = `gradle -g ${this.gradleUserHome} --no-daemon --build-cache --no-scan --quiet -DGITHUB_DEPENDENCY_GRAPH_ENABLED=false noop`
await exec.exec(gradleCommand, [], {
cwd: cleanupProjectDir cwd: cleanupProjectDir
}) })
} }

View File

@@ -2,13 +2,14 @@ import path from 'path'
import fs from 'fs' import fs from 'fs'
import * as core from '@actions/core' import * as core from '@actions/core'
import * as glob from '@actions/glob' import * as glob from '@actions/glob'
import * as semver from 'semver'
import * as params from './input-params' import * as params from './input-params'
import {META_FILE_DIR} from './cache-base' import {META_FILE_DIR} from './cache-base'
import {CacheEntryListener, CacheListener} from './cache-reporting' import {CacheEntryListener, CacheListener} from './cache-reporting'
import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils' import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'
import {loadBuildResults} from './build-results' import {BuildResult, loadBuildResults} from './build-results'
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE' const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
@@ -46,6 +47,7 @@ class ExtractedCacheEntryDefinition {
pattern: string pattern: string
bundle: boolean bundle: boolean
uniqueFileNames = true uniqueFileNames = true
notCacheableReason: string | undefined
constructor(artifactType: string, pattern: string, bundle: boolean) { constructor(artifactType: string, pattern: string, bundle: boolean) {
this.artifactType = artifactType this.artifactType = artifactType
@@ -53,10 +55,24 @@ class ExtractedCacheEntryDefinition {
this.bundle = bundle this.bundle = bundle
} }
/**
* Indicate that the file names matching the cache entry pattern are NOT sufficient to uniquely identify the contents.
* If the file names are sufficient, then we use a hash of the file names to identify the entry.
* With non-unique-file-names, we hash the file contents to identify the cache entry.
*/
withNonUniqueFileNames(): ExtractedCacheEntryDefinition { withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
this.uniqueFileNames = false this.uniqueFileNames = false
return this return this
} }
/**
* Specify that the cache entry, should not be saved for some reason, even though the contents exist.
* This is used to prevent configuration-cache entries being cached when they were generated by Gradle < 8.6,
*/
notCacheableBecause(reason: string): ExtractedCacheEntryDefinition {
this.notCacheableReason = reason
return this
}
} }
/** /**
@@ -142,6 +158,11 @@ abstract class AbstractEntryExtractor {
const artifactType = cacheEntryDefinition.artifactType const artifactType = cacheEntryDefinition.artifactType
const pattern = cacheEntryDefinition.pattern const pattern = cacheEntryDefinition.pattern
if (cacheEntryDefinition.notCacheableReason) {
listener.entry(pattern).markNotSaved(cacheEntryDefinition.notCacheableReason)
continue
}
// Find all matching files for this cache entry definition // Find all matching files for this cache entry definition
const globber = await glob.create(pattern, { const globber = await glob.create(pattern, {
implicitDescendants: false implicitDescendants: false
@@ -256,7 +277,7 @@ abstract class AbstractEntryExtractor {
} }
const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8') const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
cacheDebug(`Loaded cache metadata: ${filedata}`) cacheDebug(`Loaded cache metadata for ${this.extractorName}: ${filedata}`)
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
return extractedCacheEntryMetadata.entries return extractedCacheEntryMetadata.entries
} }
@@ -264,12 +285,12 @@ abstract class AbstractEntryExtractor {
/** /**
* Saves information about the extracted cache entries into the 'cache-metadata.json' file. * Saves information about the extracted cache entries into the 'cache-metadata.json' file.
*/ */
private saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void { protected saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void {
const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata() const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata()
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined) extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)
const filedata = JSON.stringify(extractedCacheEntryMetadata) const filedata = JSON.stringify(extractedCacheEntryMetadata)
cacheDebug(`Saving cache metadata: ${filedata}`) cacheDebug(`Saving cache metadata for ${this.extractorName}: ${filedata}`)
fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8') fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
} }
@@ -351,37 +372,96 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
* entry is not reusable. * entry is not reusable.
*/ */
async restore(listener: CacheListener): Promise<void> { async restore(listener: CacheListener): Promise<void> {
if (listener.fullyRestored) { if (!listener.fullyRestored) {
return super.restore(listener) this.markNotRestored(listener, 'Gradle User Home was not fully restored')
return
} }
core.info('Not restoring configuration-cache state, as Gradle User Home was not fully restored') if (!params.getCacheEncryptionKey()) {
for (const cacheEntry of this.loadExtractedCacheEntries()) { this.markNotRestored(listener, 'Encryption Key was not provided')
listener.entry(cacheEntry.pattern).markRequested('NOT_RESTORED') return
} }
return await super.restore(listener)
}
private markNotRestored(listener: CacheListener, reason: string): void {
const cacheEntries = this.loadExtractedCacheEntries()
if (cacheEntries.length > 0) {
core.info(`Not restoring configuration-cache state, as ${reason}`)
for (const cacheEntry of cacheEntries) {
listener.entry(cacheEntry.pattern).markNotRestored(reason)
}
// Update the results file based on no entries restored
this.saveMetadataForCacheResults([])
}
}
async extract(listener: CacheListener): Promise<void> {
if (!params.getCacheEncryptionKey()) {
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
if (cacheEntryDefinitions.length > 0) {
core.info('Not saving configuration-cache state, as no encryption key was provided')
for (const cacheEntry of cacheEntryDefinitions) {
listener.entry(cacheEntry.pattern).markNotSaved('No encryption key provided')
}
}
return
}
await super.extract(listener)
} }
/** /**
* Extract cache entries for the configuration cache in each project. * Extract cache entries for the configuration cache in each project.
*/ */
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] { protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
return this.getProjectRoots().map(projectRoot => { // Group BuildResult by existing configCacheDir
const configCachePath = path.resolve(projectRoot, '.gradle/configuration-cache') const groupedResults = this.getConfigCacheDirectoriesWithAssociatedBuildResults()
return new ExtractedCacheEntryDefinition(
return Object.entries(groupedResults).map(([configCachePath, pathResults]) => {
// Create a entry definition for each unique configuration cache directory
const definition = new ExtractedCacheEntryDefinition(
'configuration-cache', 'configuration-cache',
configCachePath, configCachePath,
true true
).withNonUniqueFileNames() ).withNonUniqueFileNames()
// If any associated build result used Gradle < 8.6, then mark it as not cacheable
if (
pathResults.find(result => {
const gradleVersion = semver.coerce(result.gradleVersion)
return gradleVersion && semver.lt(gradleVersion, '8.6.0')
})
) {
core.info(
`Not saving config-cache data for ${configCachePath}. Configuration cache data is only saved for Gradle 8.6+`
)
definition.notCacheableBecause('Configuration cache data only saved for Gradle 8.6+')
}
return definition
}) })
} }
/** private getConfigCacheDirectoriesWithAssociatedBuildResults(): Record<string, BuildResult[]> {
* For every Gradle invocation, we record the project root directory. This method returns the entire return loadBuildResults().reduce(
* set of project roots, to allow saving of configuration-cache entries for each. (acc, buildResult) => {
*/ // For each build result, find the config-cache dir
private getProjectRoots(): string[] { const configCachePath = path.resolve(buildResult.rootProjectDir, '.gradle/configuration-cache')
const buildResults = loadBuildResults() // Ignore case where config-cache dir doesn't exist
const projectRootDirs = buildResults.map(x => x.rootProjectDir) if (!fs.existsSync(configCachePath)) {
return [...new Set(projectRootDirs)] // Remove duplicates return acc
}
// Group by unique config cache directories and collect associated build results
if (!acc[configCachePath]) {
acc[configCachePath] = []
}
acc[configCachePath].push(buildResult)
return acc
},
{} as Record<string, BuildResult[]>
)
} }
} }

View File

@@ -1,4 +1,3 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache' import * as cache from '@actions/cache'
/** /**
@@ -112,47 +111,36 @@ export class CacheEntryListener {
} }
} }
export function writeCachingReport(listener: CacheListener): void { export function generateCachingReport(listener: CacheListener): string {
const entries = listener.cacheEntries const entries = listener.cacheEntries
core.summary.addRaw( return `
`\n<details><summary><h4>Caching for gradle-build-action was ${listener.cacheStatus} - expand for details</h4></summary>\n` <details>
) <summary><h4>Caching for gradle-build-action was ${listener.cacheStatus} - expand for details</h4></summary>
${renderEntryTable(entries)}
core.summary.addTable([ <h5>Cache Entry Details</h5>
[ <pre>
{data: '', header: true}, ${renderEntryDetails(listener)}
{data: 'Count', header: true},
{data: 'Total Size (Mb)', header: true}
],
['Entries Restored', `${getCount(entries, e => e.restoredSize)}`, `${getSize(entries, e => e.restoredSize)}`],
['Entries Saved', `${getCount(entries, e => e.savedSize)}`, `${getSize(entries, e => e.savedSize)}`]
])
core.summary.addHeading('Cache Entry Details', 5)
const entryDetails = renderEntryDetails(listener)
core.summary.addRaw(`<pre>
${entryDetails}
</pre> </pre>
</details> </details>
`) `
} }
export function logCachingReport(listener: CacheListener): void { function renderEntryTable(entries: CacheEntryListener[]): string {
const entries = listener.cacheEntries return `
<table>
core.startGroup(`Caching for gradle-build-action was ${listener.cacheStatus} - expand for details`) <tr><td></td><th>Count</th><th>Total Size (Mb)</th></tr>
<tr><td>Entries Restored</td>
core.info( <td>${getCount(entries, e => e.restoredSize)}</td>
`Entries Restored: ${getCount(entries, e => e.restoredSize)} (${getSize(entries, e => e.restoredSize)} Mb)` <td>${getSize(entries, e => e.restoredSize)}</td>
) </tr>
core.info(`Entries Saved : ${getCount(entries, e => e.savedSize)} (${getSize(entries, e => e.savedSize)} Mb)`) <tr><td>Entries Saved</td>
<td>${getCount(entries, e => e.savedSize)}</td>
core.info(`Cache Entry Details`) <td>${getSize(entries, e => e.savedSize)}</td>
core.info(renderEntryDetails(listener)) </tr>
</table>
core.endGroup() `
} }
function renderEntryDetails(listener: CacheListener): string { function renderEntryDetails(listener: CacheListener): string {
@@ -198,6 +186,9 @@ function getSavedMessage(entry: CacheEntryListener, cacheReadOnly: boolean): str
if (cacheReadOnly) { if (cacheReadOnly) {
return '(Entry not saved: cache is read-only)' return '(Entry not saved: cache is read-only)'
} }
if (entry.notRestored) {
return '(Entry not saved: not restored)'
}
return '(Entry not saved: reason unknown)' return '(Entry not saved: reason unknown)'
} }
if (entry.savedSize === 0) { if (entry.savedSize === 0) {

View File

@@ -11,7 +11,7 @@ import * as params from './input-params'
import {CacheEntryListener} from './cache-reporting' import {CacheEntryListener} from './cache-reporting'
const CACHE_PROTOCOL_VERSION = 'v8-' const CACHE_PROTOCOL_VERSION = 'v9-'
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX' const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT' const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
@@ -86,10 +86,10 @@ export function generateCacheKey(cacheName: string): CacheKey {
// At the most general level, share caches for all executions on the same OS // At the most general level, share caches for all executions on the same OS
const cacheKeyForEnvironment = `${cacheKeyBase}|${getCacheKeyEnvironment()}` const cacheKeyForEnvironment = `${cacheKeyBase}|${getCacheKeyEnvironment()}`
// Prefer caches that run this job // Then prefer caches that run job with the same ID
const cacheKeyForJob = `${cacheKeyForEnvironment}|${getCacheKeyJob()}` const cacheKeyForJob = `${cacheKeyForEnvironment}|${getCacheKeyJob()}`
// Prefer (even more) jobs that run this job with the same context (matrix) // Prefer (even more) jobs that run this job in the same workflow with the same context (matrix)
const cacheKeyForJobContext = `${cacheKeyForJob}[${getCacheKeyJobInstance()}]` const cacheKeyForJobContext = `${cacheKeyForJob}[${getCacheKeyJobInstance()}]`
// Exact match on Git SHA // Exact match on Git SHA
@@ -113,12 +113,7 @@ function getCacheKeyEnvironment(): string {
} }
function getCacheKeyJob(): string { function getCacheKeyJob(): string {
return process.env[CACHE_KEY_JOB_VAR] || getCacheKeyForJob(github.context.workflow, github.context.job) return process.env[CACHE_KEY_JOB_VAR] || github.context.job
}
export function getCacheKeyForJob(workflowName: string, jobId: string): string {
const sanitizedWorkflow = workflowName.replace(/,/g, '').toLowerCase()
return `${sanitizedWorkflow}-${jobId}`
} }
function getCacheKeyJobInstance(): string { function getCacheKeyJobInstance(): string {
@@ -127,25 +122,11 @@ function getCacheKeyJobInstance(): string {
return override return override
} }
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation // By default, we hash the workflow name and the full `matrix` data for the run, to uniquely identify this job invocation
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml. // The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
const workflowName = github.context.workflow
const workflowJobContext = params.getJobMatrix() const workflowJobContext = params.getJobMatrix()
return hashStrings([workflowJobContext]) return hashStrings([workflowName, workflowJobContext])
}
export function getUniqueLabelForJobInstance(): string {
return getUniqueLabelForJobInstanceValues(github.context.workflow, github.context.job, params.getJobMatrix())
}
export function getUniqueLabelForJobInstanceValues(workflow: string, jobId: string, matrixJson: string): string {
const matrix = JSON.parse(matrixJson)
const matrixString = Object.values(matrix).join('-')
const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}`
return sanitize(label)
}
function sanitize(value: string): string {
return value.replace(/[^a-zA-Z0-9_-]/g, '').toLowerCase()
} }
function getCacheKeyJobExecution(): string { function getCacheKeyJobExecution(): string {

View File

@@ -13,7 +13,7 @@ import {CacheCleaner} from './cache-cleaner'
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED' const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
export async function restore(gradleUserHome: string, cacheListener: CacheListener): Promise<void> { export async function restore(userHome: string, gradleUserHome: string, cacheListener: CacheListener): Promise<void> {
// Bypass restore cache on all but first action step in workflow. // Bypass restore cache on all but first action step in workflow.
if (process.env[CACHE_RESTORED_VAR]) { if (process.env[CACHE_RESTORED_VAR]) {
core.info('Cache only restored on first action step.') core.info('Cache only restored on first action step.')
@@ -21,7 +21,7 @@ export async function restore(gradleUserHome: string, cacheListener: CacheListen
} }
core.exportVariable(CACHE_RESTORED_VAR, true) core.exportVariable(CACHE_RESTORED_VAR, true)
const gradleStateCache = new GradleStateCache(gradleUserHome) const gradleStateCache = new GradleStateCache(userHome, gradleUserHome)
if (isCacheDisabled()) { if (isCacheDisabled()) {
core.info('Cache is disabled: will not restore state from previous builds.') core.info('Cache is disabled: will not restore state from previous builds.')
@@ -65,6 +65,7 @@ export async function restore(gradleUserHome: string, cacheListener: CacheListen
} }
export async function save( export async function save(
userHome: string,
gradleUserHome: string, gradleUserHome: string,
cacheListener: CacheListener, cacheListener: CacheListener,
daemonController: DaemonController daemonController: DaemonController
@@ -90,10 +91,14 @@ export async function save(
if (isCacheCleanupEnabled()) { if (isCacheCleanupEnabled()) {
core.info('Forcing cache cleanup.') core.info('Forcing cache cleanup.')
const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!) const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!)
await cacheCleaner.forceCleanup() try {
await cacheCleaner.forceCleanup()
} catch (e) {
core.warning(`Cache cleanup failed. Will continue. ${String(e)}`)
}
} }
await core.group('Caching Gradle state', async () => { await core.group('Caching Gradle state', async () => {
return new GradleStateCache(gradleUserHome).save(cacheListener) return new GradleStateCache(userHome, gradleUserHome).save(cacheListener)
}) })
} }

View File

@@ -1,28 +1,36 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as artifact from '@actions/artifact'
import * as github from '@actions/github' import * as github from '@actions/github'
import * as glob from '@actions/glob' import * as glob from '@actions/glob'
import * as toolCache from '@actions/tool-cache' import {DefaultArtifactClient} from '@actions/artifact'
import {Octokit} from '@octokit/rest' import {GitHub} from '@actions/github/lib/utils'
import {RequestError} from '@octokit/request-error'
import type {PullRequestEvent} from '@octokit/webhooks-types'
import * as path from 'path' import * as path from 'path'
import fs from 'fs' import fs from 'fs'
import * as layout from './repository-layout' import * as layout from './repository-layout'
import {DependencyGraphOption, getJobMatrix} from './input-params' import {DependencyGraphOption, getJobMatrix, getArtifactRetentionDays} from './input-params'
const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph' const DEPENDENCY_GRAPH_PREFIX = 'dependency-graph_'
export function setup(option: DependencyGraphOption): void { export async function setup(option: DependencyGraphOption): Promise<void> {
if (option === DependencyGraphOption.Disabled || option === DependencyGraphOption.DownloadAndSubmit) { if (option === DependencyGraphOption.Disabled) {
return
}
// Download and submit early, for compatability with dependency review.
if (option === DependencyGraphOption.DownloadAndSubmit) {
await downloadAndSubmitDependencyGraphs()
return return
} }
core.info('Enabling dependency graph generation') core.info('Enabling dependency graph generation')
const jobCorrelator = getJobCorrelator()
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'true') core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'true')
core.exportVariable('GITHUB_JOB_CORRELATOR', jobCorrelator) core.exportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR', getJobCorrelator())
core.exportVariable('GITHUB_JOB_ID', github.context.runId) core.exportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_ID', github.context.runId)
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_REF', github.context.ref)
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_SHA', getShaFromContext())
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_WORKSPACE', layout.workspaceDirectory())
core.exportVariable( core.exportVariable(
'DEPENDENCY_GRAPH_REPORT_DIR', 'DEPENDENCY_GRAPH_REPORT_DIR',
path.resolve(layout.workspaceDirectory(), 'dependency-graph-reports') path.resolve(layout.workspaceDirectory(), 'dependency-graph-reports')
@@ -30,104 +38,120 @@ export function setup(option: DependencyGraphOption): void {
} }
export async function complete(option: DependencyGraphOption): Promise<void> { export async function complete(option: DependencyGraphOption): Promise<void> {
switch (option) { try {
case DependencyGraphOption.Disabled: switch (option) {
return case DependencyGraphOption.Disabled:
case DependencyGraphOption.Generate: case DependencyGraphOption.Generate: // Performed via init-script: nothing to do here
await uploadDependencyGraphs() case DependencyGraphOption.DownloadAndSubmit: // Performed in setup
return return
case DependencyGraphOption.GenerateAndSubmit: case DependencyGraphOption.GenerateAndSubmit:
await submitDependencyGraphs(await uploadDependencyGraphs()) await submitDependencyGraphs(await findGeneratedDependencyGraphFiles())
return return
case DependencyGraphOption.DownloadAndSubmit: case DependencyGraphOption.GenerateAndUpload:
await downloadAndSubmitDependencyGraphs() await uploadDependencyGraphs(await findGeneratedDependencyGraphFiles())
}
} catch (e) {
core.warning(`Failed to ${option} dependency graph. Will continue. ${String(e)}`)
} }
} }
async function uploadDependencyGraphs(): Promise<string[]> { async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
const workspaceDirectory = layout.workspaceDirectory() const workspaceDirectory = layout.workspaceDirectory()
const graphFiles = await findDependencyGraphFiles(workspaceDirectory) return await findDependencyGraphFiles(workspaceDirectory)
}
const relativeGraphFiles = graphFiles.map(x => getRelativePathFromWorkspace(x)) async function uploadDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
core.info(`Uploading dependency graph files: ${relativeGraphFiles}`) const workspaceDirectory = layout.workspaceDirectory()
const artifactClient = artifact.create() const artifactClient = new DefaultArtifactClient()
artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, graphFiles, workspaceDirectory) for (const dependencyGraphFile of dependencyGraphFiles) {
const relativePath = getRelativePathFromWorkspace(dependencyGraphFile)
return graphFiles core.info(`Uploading dependency graph file: ${relativePath}`)
const artifactName = `${DEPENDENCY_GRAPH_PREFIX}${path.basename(dependencyGraphFile)}`
await artifactClient.uploadArtifact(artifactName, [dependencyGraphFile], workspaceDirectory, {
retentionDays: getArtifactRetentionDays()
})
}
} }
async function downloadAndSubmitDependencyGraphs(): Promise<void> { async function downloadAndSubmitDependencyGraphs(): Promise<void> {
const workspaceDirectory = layout.workspaceDirectory() try {
submitDependencyGraphs(await retrieveDependencyGraphs(workspaceDirectory)) await submitDependencyGraphs(await downloadDependencyGraphs())
} catch (e) {
core.warning(`Download and submit dependency graph failed. Will continue. ${String(e)}`)
}
} }
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> { async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
const octokit: Octokit = getOctokit()
for (const jsonFile of dependencyGraphFiles) { for (const jsonFile of dependencyGraphFiles) {
const jsonContent = fs.readFileSync(jsonFile, 'utf8') try {
await submitDependencyGraphFile(jsonFile)
const jsonObject = JSON.parse(jsonContent) } catch (error) {
jsonObject.owner = github.context.repo.owner if (error instanceof RequestError) {
jsonObject.repo = github.context.repo.repo core.warning(buildWarningMessage(jsonFile, error))
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject) } else {
throw error
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile) }
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`) }
} }
} }
async function retrieveDependencyGraphs(workspaceDirectory: string): Promise<string[]> { function buildWarningMessage(jsonFile: string, error: RequestError): string {
if (github.context.payload.workflow_run) { const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
return await retrieveDependencyGraphsForWorkflowRun(github.context.payload.workflow_run.id, workspaceDirectory) const mainWarning = `Failed to submit dependency graph ${relativeJsonFile}.\n${String(error)}`
if (error.message === 'Resource not accessible by integration') {
return `${mainWarning}
Please ensure that the 'contents: write' permission is available for the workflow job.
Note that this permission is never available for a 'pull_request' trigger from a repository fork.
`
} }
return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory) return mainWarning
} }
async function retrieveDependencyGraphsForWorkflowRun(runId: number, workspaceDirectory: string): Promise<string[]> { async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
const octokit: Octokit = getOctokit() const octokit = getOctokit()
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
// Find the workflow run artifacts named "dependency-graph" const jsonObject = JSON.parse(jsonContent)
const artifacts = await octokit.rest.actions.listWorkflowRunArtifacts({ jsonObject.owner = github.context.repo.owner
owner: github.context.repo.owner, jsonObject.repo = github.context.repo.repo
repo: github.context.repo.repo, const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
run_id: runId
})
const matchArtifact = artifacts.data.artifacts.find(candidate => { const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
return candidate.name === DEPENDENCY_GRAPH_ARTIFACT core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
})
if (matchArtifact === undefined) {
throw new Error(`Dependency graph artifact not found. Has it been generated by workflow run '${runId}'?`)
}
// Download the dependency-graph artifact
const download = await octokit.rest.actions.downloadArtifact({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip'
})
const downloadBuffer = download.data as ArrayBuffer
const downloadZip = path.resolve(workspaceDirectory, 'dependency-graph.zip')
fs.writeFileSync(downloadZip, Buffer.from(downloadBuffer))
// Expance the dependency-graph zip and locate each dependency-graph JSON file
const extractDir = path.resolve(workspaceDirectory, 'dependency-graph')
const extracted = await toolCache.extractZip(downloadZip, extractDir)
core.info(`Extracted dependency graph artifacts to ${extracted}: ${fs.readdirSync(extracted)}`)
return findDependencyGraphFiles(extracted)
} }
async function retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory: string): Promise<string[]> { async function downloadDependencyGraphs(): Promise<string[]> {
const artifactClient = artifact.create() const workspaceDirectory = layout.workspaceDirectory()
const findBy = github.context.payload.workflow_run
? {
token: getGithubToken(),
workflowRunId: github.context.payload.workflow_run.id,
repositoryName: github.context.repo.repo,
repositoryOwner: github.context.repo.owner
}
: undefined
const artifactClient = new DefaultArtifactClient()
const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph') const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph')
await artifactClient.downloadArtifact(DEPENDENCY_GRAPH_ARTIFACT, downloadPath)
return await findDependencyGraphFiles(downloadPath) const dependencyGraphArtifacts = (
await artifactClient.listArtifacts({
latest: true,
findBy
})
).artifacts.filter(candidate => candidate.name.startsWith(DEPENDENCY_GRAPH_PREFIX))
for (const artifact of dependencyGraphArtifacts) {
const downloadedArtifact = await artifactClient.downloadArtifact(artifact.id, {
path: downloadPath,
findBy
})
core.info(`Downloading dependency-graph artifact ${artifact.name} to ${downloadedArtifact.downloadPath}`)
}
return findDependencyGraphFiles(downloadPath)
} }
async function findDependencyGraphFiles(dir: string): Promise<string[]> { async function findDependencyGraphFiles(dir: string): Promise<string[]> {
@@ -136,10 +160,8 @@ async function findDependencyGraphFiles(dir: string): Promise<string[]> {
return graphFiles return graphFiles
} }
function getOctokit(): Octokit { function getOctokit(): InstanceType<typeof GitHub> {
return new Octokit({ return github.getOctokit(getGithubToken())
auth: getGithubToken()
})
} }
function getGithubToken(): string { function getGithubToken(): string {
@@ -151,7 +173,26 @@ function getRelativePathFromWorkspace(file: string): string {
return path.relative(workspaceDirectory, file) return path.relative(workspaceDirectory, file)
} }
export function getJobCorrelator(): string { function getShaFromContext(): string {
const context = github.context
const pullRequestEvents = [
'pull_request',
'pull_request_comment',
'pull_request_review',
'pull_request_review_comment'
// Note that pull_request_target is omitted here.
// That event runs in the context of the base commit of the PR,
// so the snapshot should not be associated with the head commit.
]
if (pullRequestEvents.includes(context.eventName)) {
const pr = (context.payload as PullRequestEvent).pull_request
return pr.head.sha
} else {
return context.sha
}
}
function getJobCorrelator(): string {
return constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix()) return constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix())
} }

View File

@@ -29,6 +29,10 @@ export function isCacheCleanupEnabled(): boolean {
return getBooleanInput('gradle-home-cache-cleanup') return getBooleanInput('gradle-home-cache-cleanup')
} }
export function getCacheEncryptionKey(): string {
return core.getInput('cache-encryption-key')
}
export function getCacheIncludes(): string[] { export function getCacheIncludes(): string[] {
return core.getMultilineInput('gradle-home-cache-includes') return core.getMultilineInput('gradle-home-cache-includes')
} }
@@ -67,8 +71,25 @@ export function isJobSummaryEnabled(): boolean {
return getBooleanInput('generate-job-summary', true) return getBooleanInput('generate-job-summary', true)
} }
export function isDependencyGraphEnabled(): boolean { export function getJobSummaryOption(): JobSummaryOption {
return getBooleanInput('generate-dependency-graph', true) return parseJobSummaryOption('add-job-summary')
}
export function getPRCommentOption(): JobSummaryOption {
return parseJobSummaryOption('add-job-summary-as-pr-comment')
}
function parseJobSummaryOption(paramName: string): JobSummaryOption {
const val = core.getInput(paramName)
switch (val.toLowerCase().trim()) {
case 'never':
return JobSummaryOption.Never
case 'always':
return JobSummaryOption.Always
case 'on-failure':
return JobSummaryOption.OnFailure
}
throw TypeError(`The value '${val}' is not valid for ${paramName}. Valid values are: [never, always, on-failure].`)
} }
export function getDependencyGraphOption(): DependencyGraphOption { export function getDependencyGraphOption(): DependencyGraphOption {
@@ -80,14 +101,33 @@ export function getDependencyGraphOption(): DependencyGraphOption {
return DependencyGraphOption.Generate return DependencyGraphOption.Generate
case 'generate-and-submit': case 'generate-and-submit':
return DependencyGraphOption.GenerateAndSubmit return DependencyGraphOption.GenerateAndSubmit
case 'generate-and-upload':
return DependencyGraphOption.GenerateAndUpload
case 'download-and-submit': case 'download-and-submit':
return DependencyGraphOption.DownloadAndSubmit return DependencyGraphOption.DownloadAndSubmit
} }
throw TypeError( throw TypeError(
`The value '${val} is not valid for 'dependency-graph. Valid values are: [disabled, generate-and-upload, generate-and-submit, download-and-submit]. The default value is 'disabled'.` `The value '${val}' is not valid for 'dependency-graph'. Valid values are: [disabled, generate, generate-and-submit, generate-and-upload, download-and-submit]. The default value is 'disabled'.`
) )
} }
export function getArtifactRetentionDays(): number {
const val = core.getInput('artifact-retention-days')
return parseNumericInput('artifact-retention-days', val, 0)
// Zero indicates that the default repository settings should be used
}
export function parseNumericInput(paramName: string, paramValue: string, paramDefault: number): number {
if (paramValue.length === 0) {
return paramDefault
}
const numericValue = parseInt(paramValue)
if (isNaN(numericValue)) {
throw TypeError(`The value '${paramValue}' is not a valid numeric value for '${paramName}'.`)
}
return numericValue
}
function getBooleanInput(paramName: string, paramDefault = false): boolean { function getBooleanInput(paramName: string, paramDefault = false): boolean {
const paramValue = core.getInput(paramName) const paramValue = core.getInput(paramName)
switch (paramValue.toLowerCase().trim()) { switch (paramValue.toLowerCase().trim()) {
@@ -102,8 +142,15 @@ function getBooleanInput(paramName: string, paramDefault = false): boolean {
} }
export enum DependencyGraphOption { export enum DependencyGraphOption {
Disabled, Disabled = 'disabled',
Generate, Generate = 'generate',
GenerateAndSubmit, GenerateAndSubmit = 'generate-and-submit',
DownloadAndSubmit GenerateAndUpload = 'generate-and-upload',
DownloadAndSubmit = 'download-and-submit'
}
export enum JobSummaryOption {
Never = 'never',
Always = 'always',
OnFailure = 'on-failure'
} }

View File

@@ -1,45 +1,94 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as github from '@actions/github'
import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
import {RequestError} from '@octokit/request-error'
import * as params from './input-params'
import {BuildResult} from './build-results' import {BuildResult} from './build-results'
import {writeCachingReport, CacheListener, logCachingReport} from './cache-reporting' import {CacheListener, generateCachingReport} from './cache-reporting'
export async function writeJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> { export async function generateJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> {
core.info('Writing job summary') const summaryTable = renderSummaryTable(buildResults)
const cachingReport = generateCachingReport(cacheListener)
if (buildResults.length === 0) { if (shouldGenerateJobSummary(buildResults)) {
core.debug('No Gradle build results found. Summary table will not be generated.') core.info('Generating Job Summary')
core.summary.addRaw(summaryTable)
core.summary.addRaw(cachingReport)
await core.summary.write()
} else { } else {
writeSummaryTable(buildResults) core.info('============================')
core.info(summaryTable)
core.info('============================')
core.info(cachingReport)
core.info('============================')
} }
writeCachingReport(cacheListener) if (shouldAddPRComment(buildResults)) {
await addPRComment(summaryTable)
await core.summary.write() }
} }
export async function logJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> { async function addPRComment(jobSummary: string): Promise<void> {
if (buildResults.length === 0) { const context = github.context
core.debug('No Gradle build results found. Summary table will not be logged.') if (context.payload.pull_request == null) {
} else { core.info('No pull_request trigger: not adding PR comment')
logSummaryTable(buildResults) return
} }
logCachingReport(cacheListener) const pull_request_number = context.payload.pull_request.number
core.info(`Adding Job Summary as comment to PR #${pull_request_number}.`)
const prComment = `<h3>Job Summary for gradle-build-action</h3>
<h5>${github.context.workflow} :: <em>${github.context.job}</em></h5>
${jobSummary}`
const github_token = params.getGithubToken()
const octokit = github.getOctokit(github_token)
try {
await octokit.rest.issues.createComment({
...context.repo,
issue_number: pull_request_number,
body: prComment
})
} catch (error) {
if (error instanceof RequestError) {
core.warning(buildWarningMessage(error))
} else {
throw error
}
}
} }
function writeSummaryTable(results: BuildResult[]): void { function buildWarningMessage(error: RequestError): string {
core.summary.addHeading('Gradle Builds', 3) const mainWarning = `Failed to generate PR comment.\n${String(error)}`
if (error.message === 'Resource not accessible by integration') {
return `${mainWarning}
Please ensure that the 'pull-requests: write' permission is available for the workflow job.
Note that this permission is never available for a workflow triggered from a repository fork.
`
}
return mainWarning
}
core.summary.addRaw(` function renderSummaryTable(results: BuildResult[]): string {
if (results.length === 0) {
return 'No Gradle build results detected.'
}
return `
<table> <table>
<tr> <tr>
<th>Root Project</th> <th>Gradle Root Project</th>
<th>Requested Tasks</th> <th>Requested Tasks</th>
<th>Gradle Version</th> <th>Gradle Version</th>
<th>Build Outcome</th> <th>Build Outcome</th>
<th>Build Scan®</th> <th>Build Scan®</th>
</tr>${results.map(result => renderBuildResultRow(result)).join('')} </tr>${results.map(result => renderBuildResultRow(result)).join('')}
</table> </table>
`) `
} }
function renderBuildResultRow(result: BuildResult): string { function renderBuildResultRow(result: BuildResult): string {
@@ -77,18 +126,32 @@ function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetU
return `<a href="${targetUrl}" rel="nofollow">${badgeHtml}</a>` return `<a href="${targetUrl}" rel="nofollow">${badgeHtml}</a>`
} }
function logSummaryTable(results: BuildResult[]): void { function shouldGenerateJobSummary(buildResults: BuildResult[]): boolean {
core.info('============================') // Check if Job Summary is supported on this platform
core.info('Gradle Builds') if (!process.env[SUMMARY_ENV_VAR]) {
core.info('----------------------------') return false
core.info('Root Project | Requested Tasks | Gradle Version | Build Outcome | Build Scan®') }
core.info('----------------------------')
for (const result of results) { // Check if Job Summary is disabled using the deprecated input
core.info( if (!params.isJobSummaryEnabled()) {
`${result.rootProjectName} | ${result.requestedTasks} | ${result.gradleVersion} | ${ return false
result.buildFailed ? 'FAILED' : 'SUCCESS' }
} | ${result.buildScanFailed ? 'Publish failed' : result.buildScanUri}`
) return shouldAddJobSummary(params.getJobSummaryOption(), buildResults)
}
function shouldAddPRComment(buildResults: BuildResult[]): boolean {
return shouldAddJobSummary(params.getPRCommentOption(), buildResults)
}
function shouldAddJobSummary(option: params.JobSummaryOption, buildResults: BuildResult[]): boolean {
switch (option) {
case params.JobSummaryOption.Always:
return true
case params.JobSummaryOption.Never:
return false
case params.JobSummaryOption.OnFailure:
core.info(`Got these build results: ${JSON.stringify(buildResults)}`)
return buildResults.some(result => result.buildFailed)
} }
core.info('============================')
} }

View File

@@ -50,12 +50,16 @@ abstract class BuildResultsRecorder implements BuildService<BuildResultsRecorder
if (!runnerTempDir || !githubActionStep) { if (!runnerTempDir || !githubActionStep) {
return return
} }
def buildResultsDir = new File(runnerTempDir, ".build-results") try {
buildResultsDir.mkdirs() def buildResultsDir = new File(runnerTempDir, ".build-results")
def buildResultsFile = new File(buildResultsDir, githubActionStep + getParameters().getInvocationId().get() + ".json") buildResultsDir.mkdirs()
if (!buildResultsFile.exists()) { def buildResultsFile = new File(buildResultsDir, githubActionStep + getParameters().getInvocationId().get() + ".json")
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) if (!buildResultsFile.exists()) {
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
}
} catch (Exception e) {
println "\ngradle-build-action failed to write build-results file. Will continue.\n> ${e.getLocalizedMessage()}"
} }
} }
} }

View File

@@ -121,18 +121,23 @@ class BuildResults {
if (!runnerTempDir || !githubActionStep) { if (!runnerTempDir || !githubActionStep) {
return return
} }
def buildResultsDir = new File(runnerTempDir, ".build-results")
buildResultsDir.mkdirs()
def buildResultsFile = new File(buildResultsDir, githubActionStep + invocationId + ".json")
// Overwrite any contents written by buildFinished or build service, since this result is a superset. try {
if (buildResultsFile.exists()) { def buildResultsDir = new File(runnerTempDir, ".build-results")
if (overwrite) { buildResultsDir.mkdirs()
buildResultsFile.text = groovy.json.JsonOutput.toJson(buildResults) def buildResultsFile = new File(buildResultsDir, githubActionStep + invocationId + ".json")
// Overwrite any contents written by buildFinished or build service, since this result is a superset.
if (buildResultsFile.exists()) {
if (overwrite) {
buildResultsFile.text = groovy.json.JsonOutput.toJson(buildResults)
}
} else {
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
} }
} else {
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) } catch (Exception e) {
println "\ngradle-build-action failed to write build-results file. Will continue.\n> ${e.getLocalizedMessage()}"
} }
} }
} }

View File

@@ -1,9 +1,15 @@
buildscript { buildscript {
def getInputParam = { String name ->
def envVarName = name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}
def pluginRepositoryUrl = getInputParam('gradle.plugin-repository.url') ?: 'https://plugins.gradle.org/m2'
repositories { repositories {
maven { url "https://plugins.gradle.org/m2/" } maven { url pluginRepositoryUrl }
} }
dependencies { dependencies {
classpath "org.gradle:github-dependency-graph-gradle-plugin:0.2.0" classpath "org.gradle:github-dependency-graph-gradle-plugin:1.0.0"
} }
} }
apply plugin: org.gradle.github.GitHubDependencyGraphPlugin apply plugin: org.gradle.github.GitHubDependencyGraphPlugin

View File

@@ -1,7 +1,7 @@
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
// Only run when dependency graph is explicitly enabled // Only run when dependency graph is explicitly enabled
if (System.env.GITHUB_DEPENDENCY_GRAPH_ENABLED != "true") { if (getVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED') != "true") {
return return
} }
@@ -15,10 +15,10 @@ if (GradleVersion.current().baseVersion < GradleVersion.version("5.0")) {
// This is only required for top-level builds // This is only required for top-level builds
def isTopLevelBuild = gradle.getParent() == null def isTopLevelBuild = gradle.getParent() == null
if (isTopLevelBuild) { if (isTopLevelBuild) {
def reportFile = getUniqueReportFile(System.env.GITHUB_JOB_CORRELATOR) def reportFile = getUniqueReportFile(getVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR'))
if (reportFile == null) { if (reportFile == null) {
println "::warning::No dependency snapshot generated for step. Could not determine unique job correlator - specify GITHUB_JOB_CORRELATOR var for this step." println "::warning::No dependency snapshot generated for step. Could not determine unique job correlator - specify GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR var for this step."
return return
} }
@@ -27,7 +27,6 @@ if (isTopLevelBuild) {
new File(githubOutput) << "dependency-graph-file=${reportFile.absolutePath}\n" new File(githubOutput) << "dependency-graph-file=${reportFile.absolutePath}\n"
} }
println "Generating dependency graph into '${reportFile}'" println "Generating dependency graph into '${reportFile}'"
} }
@@ -40,7 +39,7 @@ apply from: 'gradle-build-action.github-dependency-graph-gradle-plugin-apply.gro
* - When found, this value is set as a System property override. * - When found, this value is set as a System property override.
*/ */
File getUniqueReportFile(String jobCorrelator) { File getUniqueReportFile(String jobCorrelator) {
def reportDir = System.env.DEPENDENCY_GRAPH_REPORT_DIR def reportDir = getVariable('DEPENDENCY_GRAPH_REPORT_DIR')
def reportFile = new File(reportDir, jobCorrelator + ".json") def reportFile = new File(reportDir, jobCorrelator + ".json")
if (!reportFile.exists()) return reportFile if (!reportFile.exists()) return reportFile
@@ -49,7 +48,7 @@ File getUniqueReportFile(String jobCorrelator) {
def candidateCorrelator = jobCorrelator + "-" + i def candidateCorrelator = jobCorrelator + "-" + i
def candidateFile = new File(reportDir, candidateCorrelator + ".json") def candidateFile = new File(reportDir, candidateCorrelator + ".json")
if (!candidateFile.exists()) { if (!candidateFile.exists()) {
System.properties['GITHUB_JOB_CORRELATOR'] = candidateCorrelator System.properties['GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR'] = candidateCorrelator
return candidateFile return candidateFile
} }
} }
@@ -57,3 +56,10 @@ File getUniqueReportFile(String jobCorrelator) {
// Could not determine unique job correlator // Could not determine unique job correlator
return null return null
} }
/**
* Return the environment variable value, or equivalent system property (if set)
*/
String getVariable(String name) {
return System.properties[name] ?: System.getenv(name)
}

View File

@@ -168,7 +168,7 @@ if (GradleVersion.current() < GradleVersion.version('6.0')) {
} }
} }
void applyPluginExternally(PluginManager pluginManager, String pluginClassName) { void applyPluginExternally(def pluginManager, String pluginClassName) {
def externallyApplied = 'gradle.enterprise.externally-applied' def externallyApplied = 'gradle.enterprise.externally-applied'
def oldValue = System.getProperty(externallyApplied) def oldValue = System.getProperty(externallyApplied)
System.setProperty(externallyApplied, 'true') System.setProperty(externallyApplied, 'true')

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
<!-- JDK Toolchains installed by default on GitHub-hosted runners -->
<toolchain>
<type>jdk</type>
<provides>
<version>8</version>
<vendor>Eclipse Temurin</vendor>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_8_X64}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>11</version>
<vendor>Eclipse Temurin</vendor>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_11_X64}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>17</version>
<vendor>Eclipse Temurin</vendor>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_17_X64}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>21</version>
<vendor>Eclipse Temurin</vendor>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_21_X64}</jdkHome>
</configuration>
</toolchain>
</toolchains>

View File

@@ -1,23 +1,24 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as exec from '@actions/exec' import * as exec from '@actions/exec'
import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
import * as path from 'path' import * as path from 'path'
import * as os from 'os' import * as os from 'os'
import * as caches from './caches' import * as caches from './caches'
import * as layout from './repository-layout' import * as layout from './repository-layout'
import * as params from './input-params' import * as params from './input-params'
import * as dependencyGraph from './dependency-graph' import * as dependencyGraph from './dependency-graph'
import * as jobSummary from './job-summary'
import {logJobSummary, writeJobSummary} from './job-summary'
import {loadBuildResults} from './build-results' import {loadBuildResults} from './build-results'
import {CacheListener} from './cache-reporting' import {CacheListener} from './cache-reporting'
import {DaemonController} from './daemon-controller' import {DaemonController} from './daemon-controller'
const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED' const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED'
const USER_HOME = 'USER_HOME'
const GRADLE_USER_HOME = 'GRADLE_USER_HOME' const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
const CACHE_LISTENER = 'CACHE_LISTENER' const CACHE_LISTENER = 'CACHE_LISTENER'
export async function setup(): Promise<void> { export async function setup(): Promise<void> {
const userHome = await determineUserHome()
const gradleUserHome = await determineGradleUserHome() const gradleUserHome = await determineGradleUserHome()
// Bypass setup on all but first action step in workflow. // Bypass setup on all but first action step in workflow.
@@ -30,15 +31,16 @@ export async function setup(): Promise<void> {
// Record setup complete: visible in post-action, to control action completion // Record setup complete: visible in post-action, to control action completion
core.saveState(GRADLE_SETUP_VAR, true) core.saveState(GRADLE_SETUP_VAR, true)
// Save the Gradle User Home for use in the post-action step. // Save the User Home and Gradle User Home for use in the post-action step.
core.saveState(USER_HOME, userHome)
core.saveState(GRADLE_USER_HOME, gradleUserHome) core.saveState(GRADLE_USER_HOME, gradleUserHome)
const cacheListener = new CacheListener() const cacheListener = new CacheListener()
await caches.restore(gradleUserHome, cacheListener) await caches.restore(userHome, gradleUserHome, cacheListener)
core.saveState(CACHE_LISTENER, cacheListener.stringify()) core.saveState(CACHE_LISTENER, cacheListener.stringify())
dependencyGraph.setup(params.getDependencyGraphOption()) await dependencyGraph.setup(params.getDependencyGraphOption())
} }
export async function complete(): Promise<void> { export async function complete(): Promise<void> {
@@ -46,23 +48,22 @@ export async function complete(): Promise<void> {
core.info('Gradle setup post-action only performed for first gradle-build-action step in workflow.') core.info('Gradle setup post-action only performed for first gradle-build-action step in workflow.')
return return
} }
core.info('In final post-action step, saving state and writing summary') core.info('In post-action step')
const buildResults = loadBuildResults() const buildResults = loadBuildResults()
const userHome = core.getState(USER_HOME)
const gradleUserHome = core.getState(GRADLE_USER_HOME) const gradleUserHome = core.getState(GRADLE_USER_HOME)
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER)) const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
const daemonController = new DaemonController(buildResults) const daemonController = new DaemonController(buildResults)
await caches.save(gradleUserHome, cacheListener, daemonController) await caches.save(userHome, gradleUserHome, cacheListener, daemonController)
if (shouldGenerateJobSummary()) { await jobSummary.generateJobSummary(buildResults, cacheListener)
await writeJobSummary(buildResults, cacheListener)
} else {
logJobSummary(buildResults, cacheListener)
}
dependencyGraph.complete(params.getDependencyGraphOption()) await dependencyGraph.complete(params.getDependencyGraphOption())
core.info('Completed post-action step')
} }
async function determineGradleUserHome(): Promise<string> { async function determineGradleUserHome(): Promise<string> {
@@ -91,12 +92,3 @@ async function determineUserHome(): Promise<string> {
core.debug(`Determined user.home from java -version output: '${userHome}'`) core.debug(`Determined user.home from java -version output: '${userHome}'`)
return userHome return userHome
} }
function shouldGenerateJobSummary(): boolean {
// Check if Job Summary is supported on this platform
if (!process.env[SUMMARY_ENV_VAR]) {
return false
}
return params.isJobSummaryEnabled()
}

View File

@@ -20,7 +20,7 @@ dependencies {
testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') { testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') {
exclude group: 'org.codehaus.groovy', module: 'groovy-all' exclude group: 'org.codehaus.groovy', module: 'groovy-all'
} }
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2' testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.16.0'
} }
test { test {

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id "com.gradle.enterprise" version "3.14.1" id "com.gradle.enterprise" version "3.16.1"
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11.1" id "com.gradle.common-custom-user-data-gradle-plugin" version "1.12.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -16,8 +16,8 @@ import java.nio.file.Files
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
class BaseInitScriptTest extends Specification { class BaseInitScriptTest extends Specification {
static final String GE_PLUGIN_VERSION = '3.14.1' static final String GE_PLUGIN_VERSION = '3.16.1'
static final String CCUD_PLUGIN_VERSION = '1.11.1' static final String CCUD_PLUGIN_VERSION = '1.12.1'
static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9) static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)
static final TestGradleVersion GRADLE_4_X = new TestGradleVersion(GradleVersion.version('4.10.3'), 7, 10) static final TestGradleVersion GRADLE_4_X = new TestGradleVersion(GradleVersion.version('4.10.3'), 7, 10)
@@ -26,7 +26,7 @@ class BaseInitScriptTest extends Specification {
static final TestGradleVersion GRADLE_6_X = new TestGradleVersion(GradleVersion.version('6.9.4'), 8, 15) static final TestGradleVersion GRADLE_6_X = new TestGradleVersion(GradleVersion.version('6.9.4'), 8, 15)
static final TestGradleVersion GRADLE_7_X = new TestGradleVersion(GradleVersion.version('7.6.2'), 8, 19) static final TestGradleVersion GRADLE_7_X = new TestGradleVersion(GradleVersion.version('7.6.2'), 8, 19)
static final TestGradleVersion GRADLE_8_0 = new TestGradleVersion(GradleVersion.version('8.0.2'), 8, 19) static final TestGradleVersion GRADLE_8_0 = new TestGradleVersion(GradleVersion.version('8.0.2'), 8, 19)
static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.3'), 8, 19) static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.5'), 8, 19)
static final List<TestGradleVersion> ALL_VERSIONS = [ static final List<TestGradleVersion> ALL_VERSIONS = [
GRADLE_3_X, // First version where TestKit supports environment variables GRADLE_3_X, // First version where TestKit supports environment variables

View File

@@ -148,13 +148,30 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
testGradleVersion << ALL_VERSIONS testGradleVersion << ALL_VERSIONS
} }
def "produces no build results file when RUNNER_TEMP dir is not a writable directory with #testGradleVersion"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
def invalidDir = new File(testProjectDir, 'invalid-runner-temp')
invalidDir.createNewFile()
run(['help'], initScript, testGradleVersion.gradleVersion, [], [RUNNER_TEMP: invalidDir.absolutePath])
then:
def buildResultsDir = new File(testProjectDir, '.build-results')
assert !buildResultsDir.exists()
where:
testGradleVersion << ALL_VERSIONS
}
def "produces build results file with build scan when GE plugin is applied in settingsEvaluated"() { def "produces build results file with build scan when GE plugin is applied in settingsEvaluated"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm assumeTrue testGradleVersion.compatibleWithCurrentJvm
when: when:
settingsFile.text = """ settingsFile.text = """
plugins { plugins {
id 'com.gradle.enterprise' version '3.14.1' apply(false) id 'com.gradle.enterprise' version '3.16.1' apply(false)
} }
gradle.settingsEvaluated { gradle.settingsEvaluated {
apply plugin: 'com.gradle.enterprise' apply plugin: 'com.gradle.enterprise'

View File

@@ -110,11 +110,11 @@ class TestDependencyGraph extends BaseInitScriptTest {
def getEnvVars() { def getEnvVars() {
return [ return [
GITHUB_DEPENDENCY_GRAPH_ENABLED: "true", GITHUB_DEPENDENCY_GRAPH_ENABLED: "true",
GITHUB_JOB_CORRELATOR: "CORRELATOR", GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR: "CORRELATOR",
GITHUB_JOB_ID: "1", GITHUB_DEPENDENCY_GRAPH_JOB_ID: "1",
GITHUB_REF: "main", GITHUB_DEPENDENCY_GRAPH_REF: "main",
GITHUB_SHA: "123456", GITHUB_DEPENDENCY_GRAPH_SHA: "123456",
GITHUB_WORKSPACE: testProjectDir.absolutePath, GITHUB_DEPENDENCY_GRAPH_WORKSPACE: testProjectDir.absolutePath,
DEPENDENCY_GRAPH_REPORT_DIR: reportsDir.absolutePath, DEPENDENCY_GRAPH_REPORT_DIR: reportsDir.absolutePath,
GITHUB_OUTPUT: gitHubOutputFile.absolutePath GITHUB_OUTPUT: gitHubOutputFile.absolutePath
] ]

View File

@@ -49,7 +49,7 @@ test('will cleanup unused gradle versions', async () => {
const gradle802 = path.resolve(gradleUserHome, "caches/8.0.2") const gradle802 = path.resolve(gradleUserHome, "caches/8.0.2")
const wrapper802 = path.resolve(gradleUserHome, "wrapper/dists/gradle-8.0.2-bin") const wrapper802 = path.resolve(gradleUserHome, "wrapper/dists/gradle-8.0.2-bin")
const gradleCurrent = path.resolve(gradleUserHome, "caches/8.3") const gradleCurrent = path.resolve(gradleUserHome, "caches/8.5")
expect(fs.existsSync(gradle802)).toBe(true) expect(fs.existsSync(gradle802)).toBe(true)
expect(fs.existsSync(wrapper802)).toBe(true) expect(fs.existsSync(wrapper802)).toBe(true)

View File

@@ -17,10 +17,4 @@ describe('cacheUtils-utils', () => {
expect(posixHash).toBe(windowsHash) expect(posixHash).toBe(windowsHash)
}) })
}) })
describe('sanitizes workflow name in cache key', () => {
it('with comma', () => {
const cacheKey = cacheUtils.getCacheKeyForJob("Workflow, with,commas", "JOB_ID")
expect(cacheKey).toBe('workflow withcommas-JOB_ID')
})
})
}) })

View File

@@ -0,0 +1,22 @@
import * as inputParams from '../../src/input-params'
describe('input params', () => {
describe('parses numeric input', () => {
it('uses default value', () => {
const val = inputParams.parseNumericInput('param-name', '', 88)
expect(val).toBe(88)
})
it('parses numeric input', () => {
const val = inputParams.parseNumericInput('param-name', '34', 88)
expect(val).toBe(34)
})
it('fails on non-numeric input', () => {
const t = () => {
inputParams.parseNumericInput('param-name', 'xyz', 88)
};
expect(t).toThrow(TypeError)
expect(t).toThrow("The value 'xyz' is not a valid numeric value for 'param-name'.")
})
})
})