Compare commits

..

50 Commits

Author SHA1 Message Date
Daz DeBoer
a4cf152f48 Merge pull request #817 from gradle/dd/270
Prepare for 2.7.0 release
2023-07-24 17:04:07 +02:00
daz
a8aac055e2 Build outputs 2023-07-24 08:55:39 -06:00
daz
7241fa5d56 Add new output to Action.yml 2023-07-24 08:43:47 -06:00
daz
9e58f8b1de Add dependency-graph-file as step output
Fixes #804
2023-07-24 08:37:14 -06:00
daz
632e888003 Update to the latest dependency-graph plugin
- Remove experimental warning
- Update documentation
2023-07-24 08:37:14 -06:00
daz
ced6859e9c Update Build Scan™ to Build Scan® 2023-07-22 08:53:58 -06:00
daz
0904709a46 Bump GE plugin versions 2023-07-21 13:32:44 -06:00
daz
1b94073332 Bump development dependencies 2023-07-21 13:13:44 -06:00
Daz DeBoer
4821f54162 Group all npm dependencies in a single dependabot PR 2023-07-21 12:19:33 -06:00
dependabot[bot]
2dbad1ea2d Bump the github-actions group with 1 update
Bumps the github-actions group with 1 update: [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action).

- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.6.0...v2.6.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 00:08:00 +02:00
daz
915a66c096 Bump dependency-graph version number 2023-07-17 15:46:14 -06:00
daz
8e5c8782a3 Build outputs 2023-07-17 15:35:48 -06:00
daz
9f977db2d8 Update to latest plugin version 2023-07-17 15:12:30 -06:00
daz
fa27d06744 Test configuration-cache compatibility 2023-07-17 14:00:55 -06:00
Daz DeBoer
a0fdbb009a Fix issue locating wrapper bat on windows 2023-07-15 23:04:38 -06:00
daz
f59a6d4310 Avoid log messages for included builds 2023-07-15 22:33:54 -06:00
daz
b69de5f2a9 Support multiple invocations in dependency-graph init script
If an existing dependency graph file is present for the configured job correlator,
we now generate a unique correlator value for the invocation. This allows the action
to submit dependency snapshots for a series of Gradle invocations within the same Job.

This commit updates to `github-dependency-graph-gradle-plugin@v0.0.6`, which reduces
redundancy in the mapping of resolved Gradle dependencies to the GitHub Dependency Graph.
2023-07-15 22:33:31 -06:00
daz
3c11eee5f9 Don't use full path when executing gradlew
Fixes #796
2023-07-13 16:15:54 -06:00
daz
4301451b53 Bump to Gradle 8.2.1 2023-07-13 21:38:47 +02:00
daz
295170c2ce Remove dists for removed actions 2023-07-13 13:12:44 -06:00
dependabot[bot]
ce999babab Bump semver from 5.7.1 to 5.7.2
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 18:56:01 -06:00
dependabot[bot]
ce35ffa374 Bump the dev-dependencies group with 2 updates (#785)
Bumps the dev-dependencies group with 2 updates: [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser).


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

Updates `@typescript-eslint/parser` from 5.61.0 to 5.62.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/v5.62.0/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-10 18:53:25 -06:00
Daz DeBoer
ad97b0f09e Bump the github-actions group with 1 update (#784)
Bumps the github-actions group with 1 update:
[gradle/gradle-build-action](https://github.com/gradle/gradle-build-action).
2023-07-11 02:51:25 +02:00
dependabot[bot]
29c79cfd95 Bump the github-actions group with 1 update
Bumps the github-actions group with 1 update: [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action).

- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.5.1...v2.6.0)

---
updated-dependencies:
- 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-07-10 22:37:15 +00:00
Daz DeBoer
bd57605957 Remove 'experimental' from chapter title 2023-07-10 10:26:35 -06:00
Daz DeBoer
f464d5c9e5 Improve docs for dependency-graph 2023-07-10 10:23:31 -06:00
daz
cef72ff9e4 Use latest github-dependency-graph-gradle-plugin 2023-07-10 07:16:49 -06:00
Daz DeBoer
7a67f395d2 Add basic support for GitHub Dependency Graph (#782) 2023-07-08 04:57:02 +02:00
daz
bc190ca89a Build outputs 2023-07-07 20:43:20 -06:00
daz
f01b48d89d Do not attempt dependency graph on unsupported Gradle versions 2023-07-07 20:42:49 -06:00
daz
1e71bceb3f Supply plugin portal URL directly
The 'gradlePluginPortal()' convenience isn't supported in older Gradle versions.
2023-07-07 20:42:49 -06:00
Daz DeBoer
9a4d99b236 Add initial docs for dependency-graph support 2023-07-07 20:42:49 -06:00
daz
33f9bc031c Added action to clear deps for a correlator 2023-07-07 20:42:49 -06:00
daz
437bff62b6 Add basic test coverage for dependency graph
- Test workflow with dependency graph enabled
- Gradle test for init-script functionality
2023-07-07 20:42:49 -06:00
daz
c0186c5832 Replace spaces with underscore in job correlator 2023-07-07 20:42:49 -06:00
daz
ee7ca6ac9b Remove defunct generate actions 2023-07-07 20:42:48 -06:00
daz
063cc1c708 Allow flexible use of dependency-graph support
Adds a 'dependency-graph' parameter that has 4 options:
1. 'disabled': no dependency graph files generated (the default)
2. 'generate': dependency graph files will be generated and saved as artifacts.
3. 'generate-and-submit': dependency graph files will be generated, saved as artifacts,
   and submitted to the Dependency Submission API on job completion.
4. 'download-and-submit': any previously uploaded dependency graph artifacts will be downloaded
   and submitted to the Dependency Submission API.
2023-07-07 20:42:48 -06:00
daz
820b228f28 Switch back to using published plugin 2023-07-07 20:42:48 -06:00
daz
d0ffeaa089 Reduce log level for debug message 2023-07-07 20:42:48 -06:00
daz
4c9c435d2f Configure Gradle User Home for dependency-graph
Instead of requiring an action step to generate the graph, configure Gradle User Home
so that subsequent Gradle invocations can generate a graph. Any generated graph files
are uploaded as artifacts on job completion.

- Construct job.correlator from workflow/job/matrix
- Export job.correlator as an environment var
- Upload artifacts at job completion in post-action step
- Specify the location of dependency graph report
- Only apply dependency graph init script when explicitly enabled
2023-07-07 20:42:48 -06:00
daz
a6ad1901be Copy dependency graph init script to Gradle Home
- Temporarily use a hard-coded plugin for convenience
2023-07-07 20:42:48 -06:00
daz
d7761f188f Update prettier to v3.0.0 2023-07-08 04:40:54 +02:00
Daz DeBoer
92c37aaab7 Update dependencies (#779) 2023-07-08 04:12:58 +02:00
daz
1a6aca96f3 Build outputs 2023-07-07 19:56:01 -06:00
dependabot[bot]
90c9cfa90d Bump tough-cookie and @azure/ms-rest-js
Removes [tough-cookie](https://github.com/salesforce/tough-cookie). It's no longer used after updating ancestor dependency [@azure/ms-rest-js](https://github.com/Azure/ms-rest-js). These dependencies need to be updated together.


Removes `tough-cookie`

Updates `@azure/ms-rest-js` from 2.6.6 to 2.7.0
- [Changelog](https://github.com/Azure/ms-rest-js/blob/master/Changelog.md)
- [Commits](https://github.com/Azure/ms-rest-js/commits)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
- dependency-name: "@azure/ms-rest-js"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-07 19:56:01 -06:00
daz
35af09efd8 Update NPM dependencies 2023-07-07 19:56:00 -06:00
daz
00309f16a9 Use gradle-build-action@v2.5.1 2023-07-07 19:56:00 -06:00
daz
3273b6ada1 Update to Gradle 8.2
- Update all wrappers
- Update .tool-versions
- Update version to run unit tests
- Test init scripts on 8.0 and 8.X
2023-07-07 19:55:23 -06:00
Daz DeBoer
f807993b34 Configure grouped PRs for dependabot 2023-07-07 15:27:44 -06:00
daz
bde650d6f1 Update copyright notice 2023-06-30 08:57:49 -06:00
66 changed files with 20682 additions and 98977 deletions

View File

@@ -12,6 +12,7 @@
"import/no-namespace": "off", "import/no-namespace": "off",
"i18n-text/no-en": "off", "i18n-text/no-en": "off",
"no-unused-vars": "off", "no-unused-vars": "off",
"no-shadow": "off",
"sort-imports": "off", "sort-imports": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}], "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
@@ -30,6 +31,7 @@
"@typescript-eslint/no-misused-new": "error", "@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error", "@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-shadow": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error", "@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error", "@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error", "@typescript-eslint/no-useless-constructor": "error",

View File

@@ -10,12 +10,22 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
groups:
github-actions:
patterns:
- "*"
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
ignore: ignore:
- dependency-name: "@types/node" - dependency-name: "@types/node"
groups:
npm-dependencies:
patterns:
- "*"
- package-ecosystem: "gradle" - package-ecosystem: "gradle"
directory: ".github/workflow-samples/gradle-plugin" directory: ".github/workflow-samples/gradle-plugin"
registries: registries:

View File

@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -130,10 +130,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.

View File

@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -130,10 +130,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id "com.gradle.enterprise" version "3.13.4" id "com.gradle.enterprise" version "3.14"
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11" id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -130,10 +130,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.

View File

@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -130,10 +130,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.

View File

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

View File

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

View File

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

View File

@@ -29,6 +29,11 @@ jobs:
with: with:
cache-key-prefix: ${{github.run_number}}- cache-key-prefix: ${{github.run_number}}-
dependency-graph:
uses: ./.github/workflows/integ-test-dependency-graph.yml
with:
cache-key-prefix: ${{github.run_number}}-
execution-with-caching: execution-with-caching:
uses: ./.github/workflows/integ-test-execution-with-caching.yml uses: ./.github/workflows/integ-test-execution-with-caching.yml
with: with:

View File

@@ -20,7 +20,7 @@ jobs:
distribution: temurin distribution: temurin
java-version: 8 java-version: 8
- name: Setup Gradle - name: Setup Gradle
uses: gradle/gradle-build-action@v2.4.2 # Use a released version to avoid breakages uses: gradle/gradle-build-action@v2.6.1 # 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

@@ -22,7 +22,7 @@ jobs:
- name: Configure Gradle as default for unit test - name: Configure Gradle as default for unit test
uses: ./ uses: ./
with: with:
gradle-version: 8.1.1 gradle-version: 8.2.1
- name: Run tests - name: Run tests
run: | run: |
npm install npm install
@@ -50,6 +50,13 @@ jobs:
runner-os: '["ubuntu-latest"]' runner-os: '["ubuntu-latest"]'
download-dist: true download-dist: true
dependency-graph:
needs: build-distribution
uses: ./.github/workflows/integ-test-dependency-graph.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
execution-with-caching: execution-with-caching:
needs: build-distribution needs: build-distribution
uses: ./.github/workflows/integ-test-execution-with-caching.yml uses: ./.github/workflows/integ-test-execution-with-caching.yml

View File

@@ -23,10 +23,10 @@ jobs:
- name: Build kotlin-dsl project - name: Build kotlin-dsl project
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble run: ./gradlew assemble
- name: Build kotlin-dsl project without build scan - name: Build kotlin-dsl project without Build Scan®
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble check --no-scan run: ./gradlew assemble check --no-scan
- name: Build kotlin-dsl project with build scan publish failure - name: Build kotlin-dsl project with Build Scan® publish failure
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew check -Dgradle.enterprise.url=https://not.valid.server run: ./gradlew check -Dgradle.enterprise.url=https://not.valid.server
- name: Build groovy-dsl project - name: Build groovy-dsl project

View File

@@ -1,4 +1,4 @@
name: Demo adding build scan comment to PR name: Demo adding Build Scan® comment to PR
on: on:
pull_request: pull_request:
types: [assigned, review_requested] types: [assigned, review_requested]
@@ -14,7 +14,7 @@ jobs:
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" - name: "Add Build Scan URL as PR comment"
uses: actions/github-script@v6 uses: actions/github-script@v6
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} github-token: ${{secrets.GITHUB_TOKEN}}

View File

@@ -88,12 +88,12 @@ jobs:
id: gradle id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }} working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
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@v6
with: with:
script: | script: |
core.setFailed('No build scan detected') core.setFailed('No Build Scan detected')
# Test that build scans are captured when caching is disabled because Gradle User Home already exists # Test that build scans are captured when caching is disabled because Gradle User Home already exists
cache-disabled-pre-existing-gradle-home: cache-disabled-pre-existing-gradle-home:
@@ -111,12 +111,12 @@ jobs:
id: gradle id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }} working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
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@v6
with: with:
script: | script: |
core.setFailed('No build scan detected') core.setFailed('No Build Scan detected')
# Test seed the cache with cache-write-only and verify with cache-read-only # Test seed the cache with cache-write-only and verify with cache-read-only
seed-build-write-only: seed-build-write-only:

View File

@@ -0,0 +1,96 @@
name: Test execution with caching
on:
workflow_call:
inputs:
cache-key-prefix:
type: string
runner-os:
type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]'
download-dist:
type: boolean
default: false
env:
DOWNLOAD_DIST: ${{ inputs.download-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-graph-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
groovy-generate:
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: Setup Gradle for dependency-graph generate
uses: ./
with:
dependency-graph: generate
- name: Run gradle build
run: ./gradlew build
working-directory: .github/workflow-samples/groovy-dsl
kotlin-generate:
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: Setup Gradle for dependency-graph generate
uses: ./
with:
dependency-graph: generate-and-submit
- name: Run gradle build
run: ./gradlew build
working-directory: .github/workflow-samples/kotlin-dsl
submit:
needs: [groovy-generate, kotlin-generate]
runs-on: "ubuntu-latest"
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Submit dependency graphs
uses: ./
with:
dependency-graph: download-and-submit
multiple-builds:
runs-on: "ubuntu-latest"
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Setup Gradle for dependency-graph generate
uses: ./
with:
dependency-graph: generate
- id: gradle-assemble
run: ./gradlew assemble
working-directory: .github/workflow-samples/groovy-dsl
- id: gradle-build
run: ./gradlew build
working-directory: .github/workflow-samples/groovy-dsl
- name: Check generated dependency graphs
run: |
echo "gradle-assemble report file: ${{ steps.gradle-assemble.outputs.dependency-graph-file }}"
echo "gradle-build report file: ${{ steps.gradle-build.outputs.dependency-graph-file }}"
ls -l dependency-graph-reports
if ([ ! -e ${{ steps.gradle-assemble.outputs.dependency-graph-file }} ] || [ ! -e ${{ steps.gradle-build.outputs.dependency-graph-file }} ])
then
echo "Did not find expected dependency graph files"
exit 1
fi

View File

@@ -84,11 +84,11 @@ jobs:
gradle-version: ${{matrix.gradle}} gradle-version: ${{matrix.gradle}}
build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }} build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
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@v6
with: with:
script: | script: |
core.setFailed('No build scan detected') core.setFailed('No Build Scan detected')

View File

@@ -88,11 +88,11 @@ jobs:
id: gradle id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }} working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
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@v6
with: with:
script: | script: |
core.setFailed('No build scan detected') core.setFailed('No Build Scan detected')

View File

@@ -1,3 +1,3 @@
# Configuration file for asdf version manager # Configuration file for asdf version manager
nodejs 16.18.1 nodejs 16.18.1
gradle 8.1.1 gradle 8.2.1

View File

@@ -1,7 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2018 GitHub, Inc. and contributors Copyright (c) 2023 Gradle Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

147
README.md
View File

@@ -41,7 +41,7 @@ However, the `gradle-build-action` offers a number of advantages over this appro
- Easily [run the build with different versions of Gradle](#use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached. - Easily [run the build with different versions of Gradle](#use-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).
- 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).
- [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-scans) 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.
@@ -339,7 +339,7 @@ If you are using init scripts for the [Gradle Enterprise Gradle Plugin](https://
you'll need to ensure these files are applied prior to `build-result-capture.init.gradle`. 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. Since Gradle applies init scripts in alphabetical order, one way to ensure this is via file naming.
### Build scan link as Step output ### Build Scan® link as Step output
As well as reporting the [Build Scan](https://gradle.com/build-scans/) link in the Job Summary, 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`. the `gradle-build-action` action makes this link available as a Step output named `build-scan-url`.
@@ -361,7 +361,7 @@ jobs:
- name: Run build with Gradle wrapper - name: Run build with Gradle wrapper
id: gradle id: gradle
run: ./gradlew build --scan run: ./gradlew build --scan
- name: "Add build scan URL as PR comment" - name: "Add Build Scan URL as PR comment"
uses: actions/github-script@v5 uses: actions/github-script@v5
if: github.event_name == 'pull_request' && failure() if: github.event_name == 'pull_request' && failure()
with: with:
@@ -404,7 +404,146 @@ jobs:
## Support for GitHub Enterprise Server (GHES) ## Support for GitHub Enterprise Server (GHES)
You can use the `gradle-build-action` on GitHub Enterprise Server, and benefit from the improved integration with Gradle. Depending on the version of GHES you are running, certain features may be limited: You can use the `gradle-build-action` on GitHub Enterprise Server, and benefit from the improved integration with Gradle. Depending on the version of GHES you are running, certain features may be limited:
- Build scan links are captured and displayed in the GitHub Actions UI - Build Scan links are captured and displayed in the GitHub Actions UI
- Easily run your build with different versions of Gradle - Easily run your build with different versions of Gradle
- Save/restore of Gradle User Home (requires GHES v3.5+ : GitHub Actions cache was introduced in GHES 3.5) - Save/restore of Gradle User Home (requires GHES v3.5+ : GitHub Actions cache was introduced in GHES 3.5)
- Support for GitHub Actions Job Summary (requires GHES 3.6+ : GitHub Actions Job Summary support was introduced in GHES 3.6). In earlier versions of GHES the build-results summary and caching report will be written to the workflow log, as part of the post-action step. - Support for GitHub Actions Job Summary (requires GHES 3.6+ : GitHub Actions Job Summary support was introduced in GHES 3.6). In earlier versions of GHES the build-results summary and caching report will be written to the workflow log, as part of the post-action step.
# GitHub Dependency Graph support
The `gradle-build-action` has experimental support for submitting a [GitHub Dependency Graph](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph) snapshot via the [GitHub Dependency Submission API](https://docs.github.com/en/rest/dependency-graph/dependency-submission?apiVersion=2022-11-28).
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).
You enable GitHub Dependency Graph support by setting the `dependency-graph` action parameter. Valid values are:
|<div style="width:290px">Option</div> | Behaviour |
| --- |---|
| `disabled` | Do not generate a dependency graph for any build invocations.<p>This is the default. |
| `generate` | Generate a dependency graph snapshot for each build invocation, saving as a workflow artifact. |
| `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. |
- 'disabled': Do not generate a dependency graph for any build invocations. This is the default.
- 'generate': Generate a dependency graph snapshot for each build invocation, saving as a workflow artifact.
- '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.
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 simple workflow that generates and submits a dependency graph:
```yaml
name: Submit dependency graph
on:
push:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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, generating the dependency graph snapshot which will be submitted
run: ./gradlew build
```
### Filtering which Gradle Configurations contribute to the dependency graph
If you do not want to include every dependency configuration in every project in your build, you can limit the
dependency extraction to a subset of these.
To restrict which Gradle subprojects contribute to the report, specify which projects to include via a regular expression.
You can provide this value via the `DEPENDENCY_GRAPH_INCLUDE_PROJECTS` environment variable or system property.
To restrict which Gradle configurations contribute to the report, you can filter configurations by name using a regular expression.
You can provide this value via the `DEPENDENCY_GRAPH_INCLUDE_CONFIGURATIONS` environment variable or system property.
Example of a simple workflow that limits the dependency graph to `RuntimeClasspath` configuration:
```yaml
name: Submit dependency graph
on:
push:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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, generating the dependency graph from 'RuntimeClasspath' configurations
run: ./gradlew build -DDEPENDENCY_GRAPH_INCLUDE_CONFIGURATIONS=RuntimeClasspath
```
### Gradle version compatibility
The plugin should be compatible with all versions of Gradle >= 5.0, and has been tested against
Gradle versions "5.6.4", "6.9.4", "7.0.2", "7.6.2", "8.0.2" and the current Gradle release.
The plugin is compatible with running Gradle with the configuration-cache enabled. However, this support is
limited to Gradle "8.1.0" and later:
- With Gradle "8.0", the build should run successfully, but an empty dependency graph will be generated.
- With Gradle <= "7.6.4", the plugin will cause the build to fail with configuration-cache enabled.
To use this plugin with versions of Gradle older than "8.1.0", you'll need to invoke Gradle with the
configuration-cache disabled.
### Dependency snapshots generated for pull requests
This `contents: write` permission is not available for any workflow that is triggered by a pull request submitted from a forked repository, since it would permit a malicious pull request to make repository changes.
Because of this restriction, it is not possible to `generate-and-submit` a dependency graph generated for a pull-request that comes from a repository fork. In order to do so, 2 workflows will be required:
1. The first workflow runs directly against the pull request sources and will generate the dependency graph snapshot.
2. The second workflow is triggered on `workflow_run` of the first workflow, and will submit the previously saved dependency snapshots.
Note: when `download-and-submit` is used in a workflow triggered via [workflow_run](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run), the action will download snapshots saved in the triggering workflow.
***Main workflow file***
```yaml
name: run-build-and-generate-dependency-snapshot
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Gradle to generate and submit dependency graphs
uses: gradle/gradle-build-action@v2
with:
dependency-graph: generate # Only generate in this job
- name: Run a build, generating the dependency graph snapshot which will be submitted
run: ./gradlew build
```
***Dependent workflow file***
```yaml
name: submit-dependency-snapshot
on:
workflow_run:
workflows: ['run-build-and-generate-dependency-snapshot']
types: [completed]
jobs:
submit-snapshots:
runs-on: ubuntu-latest
steps:
- name: Retrieve dependency graph artifact and submit
uses: gradle/gradle-build-action@v2
with:
dependency-graph: download-and-submit
```

View File

@@ -58,6 +58,11 @@ inputs:
required: false required: false
default: true default: true
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.
# These properties are experimental and not (yet) designed for production use, and may change without notice in a subsequent release of `gradle-build-action`. # These properties are experimental and not (yet) designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
@@ -75,9 +80,16 @@ inputs:
required: false required: false
default: false default: false
github-token:
description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
default: ${{ github.token }}
required: false
outputs: outputs:
build-scan-url: build-scan-url:
description: Link to the build scan if any description: Link to the Build Scan® generated by a Gradle build. Note that this output applies to a Step executing Gradle, not to the `gradle-build-action` Step itself.
dependency-graph-file:
description: Path to the GitHub Dependency Graph snapshot file generated by a Gradle build. Note that this output applies to a Step executing Gradle, not to the `gradle-build-action` Step itself.
runs: runs:
using: 'node16' using: 'node16'

View File

@@ -0,0 +1,24 @@
name: 'Clear dependency graph for a correlator'
inputs:
job-correlator:
required: true
runs:
using: "composite"
steps:
- name: Set current timestamp as env variable
shell: bash
run: echo "NOW=$(date -Iseconds)" >> $GITHUB_ENV
- name: Submit empty dependency graph
shell: bash
run: |
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ github.token }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${{ github.repository }}/dependency-graph/snapshots \
-d '{ "version" : 0, "job" : { "id" : "${{ github.run_id }}", "correlator" : "${{ inputs.job-correlator }} " }, "sha" : "${{ github.sha }}", "ref" : "${{ github.ref }}", "detector" : { "name" : "GitHub Dependency Graph Gradle Plugin", "version" : "0.0.3", "url" : "https://github.com/gradle/github-dependency-graph-gradle-plugin" }, "manifests" : {}, "scanned" : "${{ env.NOW }}" }'
- run: echo "::notice ::Cleared dependency graph for job correlator '${{ inputs.job-correlator }}'"
shell: bash

View File

@@ -1,19 +0,0 @@
name: "Dependency Graph Generate"
description: Calculates the complete dependency graph for the repository, saving it as a JSON artifact.
inputs:
gradle-version:
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
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
runs:
using: 'node16'
main: '../../dist/dependency-graph-generate/index.js'

View File

@@ -1,12 +0,0 @@
name: "Dependency Graph Submit"
description: Retrieves a previously created dependency graph JSON and submits via the GitHub Dependency Submission API.
inputs:
github-token:
description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
default: ${{ github.token }}
required: false
runs:
using: 'node16'
main: '../../dist/dependency-graph-submit/index.js'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8615
dist/main/index.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

9473
dist/post/index.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2936
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,7 @@
"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-dependency-graph-generate": "ncc build src/dependency-graph-generate.ts --out dist/dependency-graph-generate --source-map --no-source-map-register", "compile": "npm run compile-main && npm run compile-post",
"compile-dependency-graph-submit": "ncc build src/dependency-graph-submit.ts --out dist/dependency-graph-submit --source-map --no-source-map-register",
"compile": "npm run compile-main && npm run compile-post && npm run compile-dependency-graph-generate && npm run compile-dependency-graph-submit",
"test": "jest", "test": "jest",
"check": "npm run format && npm run lint", "check": "npm run format && npm run lint",
@@ -40,23 +38,24 @@
"@actions/glob": "0.4.0", "@actions/glob": "0.4.0",
"@actions/http-client": "2.1.0", "@actions/http-client": "2.1.0",
"@actions/tool-cache": "2.0.1", "@actions/tool-cache": "2.0.1",
"@octokit/rest": "19.0.11", "@octokit/rest": "19.0.13",
"string-argv": "0.3.2" "string-argv": "0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "16.11.21", "@types/node": "16.18.38",
"@types/jest": "29.5.2", "@types/jest": "29.5.3",
"@types/unzipper": "0.10.6", "@types/unzipper": "0.10.6",
"@typescript-eslint/parser": "5.60.1", "@typescript-eslint/parser": "6.1.0",
"@vercel/ncc": "0.36.1", "@vercel/ncc": "0.36.1",
"eslint": "8.43.0", "eslint": "8.45.0",
"eslint-plugin-github": "4.8.0", "eslint-plugin-github": "4.9.2",
"eslint-plugin-jest": "27.2.1", "eslint-plugin-jest": "27.2.3",
"jest": "29.5.0", "eslint-plugin-prettier": "5.0.0",
"jest": "29.6.1",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"patch-package": "7.0.0", "patch-package": "7.0.0",
"prettier": "2.8.8", "prettier": "3.0.0",
"ts-jest": "29.1.0", "ts-jest": "29.1.1",
"typescript": "5.1.5" "typescript": "5.1.6"
} }
} }

View File

@@ -172,7 +172,12 @@ export class GradleStateCache {
} }
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void { private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void {
const initScriptFilenames = ['build-result-capture.init.gradle', 'build-result-capture-service.plugin.groovy'] const initScriptFilenames = [
'build-result-capture.init.gradle',
'build-result-capture-service.plugin.groovy',
'github-dependency-graph.init.gradle',
'github-dependency-graph-gradle-plugin-apply.groovy'
]
for (const initScriptFilename of initScriptFilenames) { for (const initScriptFilename of initScriptFilenames) {
const initScriptContent = this.readInitScriptAsString(initScriptFilename) const initScriptContent = this.readInitScriptAsString(initScriptFilename)
const initScriptPath = path.resolve(initScriptsDir, initScriptFilename) const initScriptPath = path.resolve(initScriptsDir, initScriptFilename)

View File

@@ -125,10 +125,25 @@ function getCacheKeyJobInstance(): string {
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation // By default, we hash 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 workflowJobContext = params.getJobContext() const workflowJobContext = params.getJobMatrix()
return hashStrings([workflowJobContext]) return hashStrings([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 {
// Used to associate a cache key with a particular execution (default is bound to the git commit sha) // Used to associate a cache key with a particular execution (default is bound to the git commit sha)
return process.env[CACHE_KEY_JOB_EXECUTION_VAR] || github.context.sha return process.env[CACHE_KEY_JOB_EXECUTION_VAR] || github.context.sha

View File

@@ -1,24 +0,0 @@
import * as core from '@actions/core'
import * as provisioner from './provision'
import * as dependencyGraph from './dependency-graph'
/**
* The main entry point for the action, called by Github Actions for the step.
*/
export async function run(): Promise<void> {
try {
// Download and install Gradle if required
const executable = await provisioner.provisionGradle()
// Generate and upload dependency graph artifact
await dependencyGraph.generateDependencyGraph(executable)
} catch (error) {
core.setFailed(String(error))
if (error instanceof Error && error.stack) {
core.info(error.stack)
}
}
}
run()

View File

@@ -1,16 +0,0 @@
import * as core from '@actions/core'
import * as dependencyGraph from './dependency-graph'
export async function run(): Promise<void> {
try {
// Retrieve the dependency graph artifact and submit via Dependency Submission API
await dependencyGraph.submitDependencyGraph()
} catch (error) {
core.setFailed(String(error))
if (error instanceof Error && error.stack) {
core.info(error.stack)
}
}
}
run()

View File

@@ -8,59 +8,64 @@ import {Octokit} from '@octokit/rest'
import * as path from 'path' import * as path from 'path'
import fs from 'fs' import fs from 'fs'
import * as execution from './execution'
import * as layout from './repository-layout' import * as layout from './repository-layout'
import {DependencyGraphOption, getJobMatrix} from './input-params'
const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph' const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph'
const DEPENDENCY_GRAPH_FILE = 'dependency-graph.json'
export async function generateDependencyGraph(executable: string | undefined): Promise<void> { export function setup(option: DependencyGraphOption): void {
const workspaceDirectory = layout.workspaceDirectory() if (option === DependencyGraphOption.Disabled || option === DependencyGraphOption.DownloadAndSubmit) {
const buildRootDirectory = layout.buildRootDirectory() return
const buildPath = getRelativePathFromWorkspace(buildRootDirectory) }
const initScript = path.resolve( core.info('Enabling dependency graph generation')
__dirname, const jobCorrelator = getJobCorrelator()
'..', core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'true')
'..', core.exportVariable('GITHUB_JOB_CORRELATOR', jobCorrelator)
'src', core.exportVariable('GITHUB_JOB_ID', github.context.runId)
'resources', core.exportVariable(
'init-scripts', 'DEPENDENCY_GRAPH_REPORT_DIR',
'github-dependency-graph.init.gradle' path.resolve(layout.workspaceDirectory(), 'dependency-graph-reports')
) )
const args = [ }
`-Dorg.gradle.github.env.GRADLE_BUILD_PATH=${buildPath}`,
'--init-script',
initScript,
':GitHubDependencyGraphPlugin_generateDependencyGraph'
]
await execution.executeGradleBuild(executable, buildRootDirectory, args) export async function complete(option: DependencyGraphOption): Promise<void> {
const dependencyGraphJson = copyDependencyGraphToBuildRoot(buildRootDirectory) switch (option) {
case DependencyGraphOption.Disabled:
return
case DependencyGraphOption.Generate:
await uploadDependencyGraphs()
return
case DependencyGraphOption.GenerateAndSubmit:
await submitDependencyGraphs(await uploadDependencyGraphs())
return
case DependencyGraphOption.DownloadAndSubmit:
await downloadAndSubmitDependencyGraphs()
}
}
async function uploadDependencyGraphs(): Promise<string[]> {
const workspaceDirectory = layout.workspaceDirectory()
const graphFiles = await findDependencyGraphFiles(workspaceDirectory)
const relativeGraphFiles = graphFiles.map(x => getRelativePathFromWorkspace(x))
core.info(`Uploading dependency graph files: ${relativeGraphFiles}`)
const artifactClient = artifact.create() const artifactClient = artifact.create()
artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, [dependencyGraphJson], workspaceDirectory) artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, graphFiles, workspaceDirectory)
return graphFiles
} }
function copyDependencyGraphToBuildRoot(buildRootDirectory: string): string { async function downloadAndSubmitDependencyGraphs(): Promise<void> {
const sourceFile = path.resolve(
buildRootDirectory,
'build',
'reports',
'github-dependency-graph-plugin',
'github-dependency-snapshot.json'
)
const destFile = path.resolve(buildRootDirectory, DEPENDENCY_GRAPH_FILE)
fs.copyFileSync(sourceFile, destFile)
return destFile
}
export async function submitDependencyGraph(): Promise<void> {
const workspaceDirectory = layout.workspaceDirectory() const workspaceDirectory = layout.workspaceDirectory()
submitDependencyGraphs(await retrieveDependencyGraphs(workspaceDirectory))
}
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
const octokit: Octokit = getOctokit() const octokit: Octokit = getOctokit()
for (const jsonFile of await retrieveDependencyGraphs(octokit, workspaceDirectory)) { for (const jsonFile of dependencyGraphFiles) {
const jsonContent = fs.readFileSync(jsonFile, 'utf8') const jsonContent = fs.readFileSync(jsonFile, 'utf8')
const jsonObject = JSON.parse(jsonContent) const jsonObject = JSON.parse(jsonContent)
@@ -69,34 +74,20 @@ export async function submitDependencyGraph(): Promise<void> {
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject) const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile) const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
core.info(`Submitted ${relativeJsonFile}: ${JSON.stringify(response)}`)
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`) core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
} }
} }
async function findDependencyGraphFiles(dir: string): Promise<string[]> { async function retrieveDependencyGraphs(workspaceDirectory: string): Promise<string[]> {
const globber = await glob.create(`${dir}/**/${DEPENDENCY_GRAPH_FILE}`)
const graphFiles = globber.glob()
core.info(`Found graph files in ${dir}: ${graphFiles}`)
return graphFiles
}
async function retrieveDependencyGraphs(octokit: Octokit, workspaceDirectory: string): Promise<string[]> {
if (github.context.payload.workflow_run) { if (github.context.payload.workflow_run) {
return await retrieveDependencyGraphsForWorkflowRun( return await retrieveDependencyGraphsForWorkflowRun(github.context.payload.workflow_run.id, workspaceDirectory)
github.context.payload.workflow_run.id,
octokit,
workspaceDirectory
)
} }
return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory) return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory)
} }
async function retrieveDependencyGraphsForWorkflowRun( async function retrieveDependencyGraphsForWorkflowRun(runId: number, workspaceDirectory: string): Promise<string[]> {
runId: number, const octokit: Octokit = getOctokit()
octokit: Octokit,
workspaceDirectory: string
): Promise<string[]> {
// Find the workflow run artifacts named "dependency-graph" // Find the workflow run artifacts named "dependency-graph"
const artifacts = await octokit.rest.actions.listWorkflowRunArtifacts({ const artifacts = await octokit.rest.actions.listWorkflowRunArtifacts({
owner: github.context.repo.owner, owner: github.context.repo.owner,
@@ -139,6 +130,12 @@ async function retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory: st
return await findDependencyGraphFiles(downloadPath) return await findDependencyGraphFiles(downloadPath)
} }
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`)
const graphFiles = globber.glob()
return graphFiles
}
function getOctokit(): Octokit { function getOctokit(): Octokit {
return new Octokit({ return new Octokit({
auth: getGithubToken() auth: getGithubToken()
@@ -153,3 +150,29 @@ function getRelativePathFromWorkspace(file: string): string {
const workspaceDirectory = layout.workspaceDirectory() const workspaceDirectory = layout.workspaceDirectory()
return path.relative(workspaceDirectory, file) return path.relative(workspaceDirectory, file)
} }
export function getJobCorrelator(): string {
return constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix())
}
export function constructJobCorrelator(workflow: string, jobId: string, matrixJson: string): string {
const matrixString = describeMatrix(matrixJson)
const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}`
return sanitize(label)
}
function describeMatrix(matrixJson: string): string {
core.debug(`Got matrix json: ${matrixJson}`)
const matrix = JSON.parse(matrixJson)
if (matrix) {
return Object.values(matrix).join('-')
}
return ''
}
function sanitize(value: string): string {
return value
.replace(/[^a-zA-Z0-9_-\s]/g, '')
.replace(/\s+/g, '_')
.toLowerCase()
}

View File

@@ -1,12 +1,11 @@
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 fs from 'fs'
import * as gradlew from './gradlew' import * as gradlew from './gradlew'
export async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> { export async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> {
// Use the provided executable, or look for a Gradle wrapper script to run // Use the provided executable, or look for a Gradle wrapper script to run
const toExecute = executable ?? gradlew.locateGradleWrapperScript(root) const toExecute = executable ?? gradlew.gradleWrapperScript(root)
verifyIsExecutableScript(toExecute)
const status: number = await exec.exec(toExecute, args, { const status: number = await exec.exec(toExecute, args, {
cwd: root, cwd: root,
ignoreReturnCode: true ignoreReturnCode: true
@@ -16,11 +15,3 @@ export async function executeGradleBuild(executable: string | undefined, root: s
core.setFailed(`Gradle build failed: see console output for details`) core.setFailed(`Gradle build failed: see console output for details`)
} }
} }
function verifyIsExecutableScript(toExecute: string): void {
try {
fs.accessSync(toExecute, fs.constants.X_OK)
} catch (err) {
throw new Error(`Gradle script '${toExecute}' is not executable.`)
}
}

View File

@@ -4,23 +4,39 @@ import fs from 'fs'
const IS_WINDOWS = process.platform === 'win32' const IS_WINDOWS = process.platform === 'win32'
export function wrapperScriptFilename(): string { export function wrapperScriptFilename(): string {
return IS_WINDOWS ? 'gradlew.bat' : 'gradlew' return IS_WINDOWS ? './gradlew.bat' : './gradlew'
} }
export function installScriptFilename(): string { export function installScriptFilename(): string {
return IS_WINDOWS ? 'gradle.bat' : 'gradle' return IS_WINDOWS ? 'gradle.bat' : 'gradle'
} }
export function locateGradleWrapperScript(buildRootDirectory: string): string { export function gradleWrapperScript(buildRootDirectory: string): string {
validateGradleWrapper(buildRootDirectory) validateGradleWrapper(buildRootDirectory)
return path.resolve(buildRootDirectory, wrapperScriptFilename()) return wrapperScriptFilename()
} }
function validateGradleWrapper(buildRootDirectory: string): void { function validateGradleWrapper(buildRootDirectory: string): void {
const wrapperScript = path.resolve(buildRootDirectory, wrapperScriptFilename())
verifyExists(wrapperScript, 'Gradle Wrapper script')
verifyIsExecutableScript(wrapperScript)
const wrapperProperties = path.resolve(buildRootDirectory, 'gradle/wrapper/gradle-wrapper.properties') const wrapperProperties = path.resolve(buildRootDirectory, 'gradle/wrapper/gradle-wrapper.properties')
if (!fs.existsSync(wrapperProperties)) { verifyExists(wrapperProperties, 'Gradle wrapper properties file')
}
function verifyExists(file: string, description: string): void {
if (!fs.existsSync(file)) {
throw new Error( throw new Error(
`Cannot locate a Gradle wrapper properties file at '${wrapperProperties}'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.` `Cannot locate ${description} at '${file}'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.`
) )
} }
} }
function verifyIsExecutableScript(toExecute: string): void {
try {
fs.accessSync(toExecute, fs.constants.X_OK)
} catch (err) {
throw new Error(`Gradle script '${toExecute}' is not executable.`)
}
}

View File

@@ -51,7 +51,7 @@ export function getArguments(): string[] {
} }
// Internal parameters // Internal parameters
export function getJobContext(): string { export function getJobMatrix(): string {
return core.getInput('workflow-job-context') return core.getInput('workflow-job-context')
} }
@@ -63,6 +63,27 @@ export function isJobSummaryEnabled(): boolean {
return getBooleanInput('generate-job-summary', true) return getBooleanInput('generate-job-summary', true)
} }
export function isDependencyGraphEnabled(): boolean {
return getBooleanInput('generate-dependency-graph', true)
}
export function getDependencyGraphOption(): DependencyGraphOption {
const val = core.getInput('dependency-graph')
switch (val.toLowerCase().trim()) {
case 'disabled':
return DependencyGraphOption.Disabled
case 'generate':
return DependencyGraphOption.Generate
case 'generate-and-submit':
return DependencyGraphOption.GenerateAndSubmit
case 'download-and-submit':
return DependencyGraphOption.DownloadAndSubmit
}
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'.`
)
}
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()) {
@@ -75,3 +96,10 @@ function getBooleanInput(paramName: string, paramDefault = false): boolean {
} }
throw TypeError(`The value '${paramValue} is not valid for '${paramName}. Valid values are: [true, false]`) throw TypeError(`The value '${paramValue} is not valid for '${paramName}. Valid values are: [true, false]`)
} }
export enum DependencyGraphOption {
Disabled,
Generate,
GenerateAndSubmit,
DownloadAndSubmit
}

View File

@@ -36,7 +36,7 @@ function writeSummaryTable(results: BuildResult[]): void {
<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>
`) `)
@@ -72,7 +72,7 @@ function renderBuildScan(result: BuildResult): string {
} }
function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetUrl: string): string { function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetUrl: string): string {
const badgeUrl = `https://img.shields.io/badge/Build%20Scan%E2%84%A2-${outcomeText}-${outcomeColor}?logo=Gradle` const badgeUrl = `https://img.shields.io/badge/Build%20Scan%C2%AE-${outcomeText}-${outcomeColor}?logo=Gradle`
const badgeHtml = `<img src="${badgeUrl}" alt="Build Scan ${outcomeText}" />` const badgeHtml = `<img src="${badgeUrl}" alt="Build Scan ${outcomeText}" />`
return `<a href="${targetUrl}" rel="nofollow">${badgeHtml}</a>` return `<a href="${targetUrl}" rel="nofollow">${badgeHtml}</a>`
} }
@@ -81,7 +81,7 @@ function logSummaryTable(results: BuildResult[]): void {
core.info('============================') core.info('============================')
core.info('Gradle Builds') core.info('Gradle Builds')
core.info('----------------------------') core.info('----------------------------')
core.info('Root Project | Requested Tasks | Gradle Version | Build Outcome | Build Scan') core.info('Root Project | Requested Tasks | Gradle Version | Build Outcome | Build Scan®')
core.info('----------------------------') core.info('----------------------------')
for (const result of results) { for (const result of results) {
core.info( core.info(

View File

@@ -23,7 +23,7 @@ if (isTopLevelBuild) {
captureUsingBuildFinished(gradle, invocationId) captureUsingBuildFinished(gradle, invocationId)
} }
// The `buildScanPublished` hook allows the capture of the build scan URI. // The `buildScanPublished` hook allows the capture of the Build Scan URI.
// Results captured this way will overwrite any results from the other mechanism. // Results captured this way will overwrite any results from the other mechanism.
settings.pluginManager.withPlugin("com.gradle.enterprise") { settings.pluginManager.withPlugin("com.gradle.enterprise") {
captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject, invocationId) captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject, invocationId)
@@ -34,7 +34,7 @@ if (isTopLevelBuild) {
// By default, use 'buildFinished' to capture build results // By default, use 'buildFinished' to capture build results
captureUsingBuildFinished(gradle, invocationId) captureUsingBuildFinished(gradle, invocationId)
// The `buildScanPublished` hook allows the capture of the build scan URI. // The `buildScanPublished` hook allows the capture of the Build Scan URI.
// Results captured this way will overwrite any results from 'buildFinished'. // Results captured this way will overwrite any results from 'buildFinished'.
gradle.rootProject.pluginManager.withPlugin("com.gradle.build-scan") { gradle.rootProject.pluginManager.withPlugin("com.gradle.build-scan") {
captureUsingBuildScanPublished(gradle.rootProject.extensions["buildScan"], gradle.rootProject, invocationId) captureUsingBuildScanPublished(gradle.rootProject.extensions["buildScan"], gradle.rootProject, invocationId)

View File

@@ -0,0 +1,9 @@
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.gradle:github-dependency-graph-gradle-plugin:0.2.0"
}
}
apply plugin: org.gradle.github.GitHubDependencyGraphPlugin

View File

@@ -1,12 +1,59 @@
import org.gradle.github.GitHubDependencyGraphPlugin import org.gradle.util.GradleVersion
initscript {
repositories { // Only run when dependency graph is explicitly enabled
maven { if (System.env.GITHUB_DEPENDENCY_GRAPH_ENABLED != "true") {
url = uri("https://plugins.gradle.org/m2/") return
} }
}
dependencies { // Do not run for unsupported versions of Gradle
classpath("org.gradle:github-dependency-graph-gradle-plugin:+") if (GradleVersion.current().baseVersion < GradleVersion.version("5.0")) {
} println "::warning::Dependency Graph is not supported for Gradle versions < 5.0. No dependency snapshot will be generated."
return
}
// Attempt to find a unique job correlator to use based on the environment variable
// This is only required for top-level builds
def isTopLevelBuild = gradle.getParent() == null
if (isTopLevelBuild) {
def reportFile = getUniqueReportFile(System.env.GITHUB_JOB_CORRELATOR)
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."
return
}
def githubOutput = System.getenv("GITHUB_OUTPUT")
if (githubOutput) {
new File(githubOutput) << "dependency-graph-file=${reportFile.absolutePath}\n"
}
println "Generating dependency graph into '${reportFile}'"
}
apply from: 'github-dependency-graph-gradle-plugin-apply.groovy'
/**
* Using the supplied jobCorrelator value:
* - Checks if report file already exists
* - If so, tries to find a unique value that does not yet have a corresponding report file.
* - When found, this value is set as a System property override.
*/
File getUniqueReportFile(String jobCorrelator) {
def reportDir = System.env.DEPENDENCY_GRAPH_REPORT_DIR
def reportFile = new File(reportDir, jobCorrelator + ".json")
if (!reportFile.exists()) return reportFile
// Try at most 100 suffixes
for (int i = 1; i < 100; i++) {
def candidateCorrelator = jobCorrelator + "-" + i
def candidateFile = new File(reportDir, candidateCorrelator + ".json")
if (!candidateFile.exists()) {
System.properties['GITHUB_JOB_CORRELATOR'] = candidateCorrelator
return candidateFile
}
}
// Could not determine unique job correlator
return null
} }
apply plugin: GitHubDependencyGraphPlugin

View File

@@ -6,6 +6,7 @@ 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 {logJobSummary, writeJobSummary} from './job-summary' import {logJobSummary, writeJobSummary} from './job-summary'
import {loadBuildResults} from './build-results' import {loadBuildResults} from './build-results'
@@ -36,6 +37,8 @@ export async function setup(): Promise<void> {
await caches.restore(gradleUserHome, cacheListener) await caches.restore(gradleUserHome, cacheListener)
core.saveState(CACHE_LISTENER, cacheListener.stringify()) core.saveState(CACHE_LISTENER, cacheListener.stringify())
dependencyGraph.setup(params.getDependencyGraphOption())
} }
export async function complete(): Promise<void> { export async function complete(): Promise<void> {
@@ -58,6 +61,8 @@ export async function complete(): Promise<void> {
} else { } else {
logJobSummary(buildResults, cacheListener) logJobSummary(buildResults, cacheListener)
} }
dependencyGraph.complete(params.getDependencyGraphOption())
} }
async function determineGradleUserHome(): Promise<string> { async function determineGradleUserHome(): Promise<string> {

View File

@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -130,10 +130,13 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id "com.gradle.enterprise" version "3.13.4" id "com.gradle.enterprise" version "3.14"
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11" id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11.1"
} }
gradleEnterprise { gradleEnterprise {

View File

@@ -22,8 +22,9 @@ class BaseInitScriptTest extends Specification {
static final TestGradleVersion GRADLE_5_X = new TestGradleVersion(GradleVersion.version('5.6.4'), 8, 12) static final TestGradleVersion GRADLE_5_X = new TestGradleVersion(GradleVersion.version('5.6.4'), 8, 12)
static final TestGradleVersion GRADLE_6_NO_BUILD_SERVICE = new TestGradleVersion(GradleVersion.version('6.5.1'), 8, 14) static final TestGradleVersion GRADLE_6_NO_BUILD_SERVICE = new TestGradleVersion(GradleVersion.version('6.5.1'), 8, 14)
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.1'), 8, 19) static final TestGradleVersion GRADLE_7_X = new TestGradleVersion(GradleVersion.version('7.6.2'), 8, 19)
static final TestGradleVersion GRADLE_8_X = 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.2.1'), 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
@@ -32,14 +33,15 @@ class BaseInitScriptTest extends Specification {
GRADLE_6_NO_BUILD_SERVICE, // Last version without build service support GRADLE_6_NO_BUILD_SERVICE, // Last version without build service support
GRADLE_6_X, GRADLE_6_X,
GRADLE_7_X, GRADLE_7_X,
GRADLE_8_0,
GRADLE_8_X, GRADLE_8_X,
] ]
static final List<TestGradleVersion> CONFIGURATION_CACHE_VERSIONS = static final List<TestGradleVersion> CONFIGURATION_CACHE_VERSIONS =
[GRADLE_7_X, GRADLE_8_X] [GRADLE_7_X, GRADLE_8_0, GRADLE_8_X]
static final List<TestGradleVersion> SETTINGS_PLUGIN_VERSIONS = static final List<TestGradleVersion> SETTINGS_PLUGIN_VERSIONS =
[GRADLE_6_X, GRADLE_7_X, GRADLE_8_X] [GRADLE_6_X, GRADLE_7_X, GRADLE_8_0, GRADLE_8_X]
static final String PUBLIC_BUILD_SCAN_ID = 'i2wepy2gr7ovw' static final String PUBLIC_BUILD_SCAN_ID = 'i2wepy2gr7ovw'
static final String DEFAULT_SCAN_UPLOAD_TOKEN = 'scan-upload-token' static final String DEFAULT_SCAN_UPLOAD_TOKEN = 'scan-upload-token'
@@ -137,7 +139,7 @@ class BaseInitScriptTest extends Specification {
} else { } else {
""" """
plugins { plugins {
id 'com.gradle.enterprise' version '3.13.4' id 'com.gradle.enterprise' version '3.14'
} }
gradleEnterprise { gradleEnterprise {
server = '$mockScansServer.address' server = '$mockScansServer.address'
@@ -163,7 +165,7 @@ class BaseInitScriptTest extends Specification {
} else if (gradleVersion < GradleVersion.version('6.0')) { } else if (gradleVersion < GradleVersion.version('6.0')) {
""" """
plugins { plugins {
id 'com.gradle.build-scan' version '3.13.4' id 'com.gradle.build-scan' version '3.14'
} }
gradleEnterprise { gradleEnterprise {
server = '$mockScansServer.address' server = '$mockScansServer.address'

View File

@@ -154,7 +154,7 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
when: when:
settingsFile.text = """ settingsFile.text = """
plugins { plugins {
id 'com.gradle.enterprise' version '3.13.4' apply(false) id 'com.gradle.enterprise' version '3.14' apply(false)
} }
gradle.settingsEvaluated { gradle.settingsEvaluated {
apply plugin: 'com.gradle.enterprise' apply plugin: 'com.gradle.enterprise'

View File

@@ -0,0 +1,134 @@
package com.gradle.gradlebuildaction
import static org.junit.Assume.assumeTrue
class TestDependencyGraph extends BaseInitScriptTest {
def initScript = 'github-dependency-graph.init.gradle'
static final List<TestGradleVersion> NO_DEPENDENCY_GRAPH_VERSIONS = [GRADLE_3_X, GRADLE_4_X]
static final List<TestGradleVersion> DEPENDENCY_GRAPH_VERSIONS = ALL_VERSIONS - NO_DEPENDENCY_GRAPH_VERSIONS
def "does not produce dependency graph when not enabled"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
run(['help'], initScript, testGradleVersion.gradleVersion)
then:
assert !reportsDir.exists()
where:
testGradleVersion << ALL_VERSIONS
}
def "produces dependency graph when enabled"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert reportFile.exists()
assert gitHubOutputFile.text == "dependency-graph-file=${reportFile.absolutePath}\n"
where:
testGradleVersion << GRADLE_8_X
}
// Dependency-graph plugin doesn't support config-cache for 8.0 of Gradle
def "produces dependency graph with configuration-cache on latest Gradle"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert reportFile.exists()
where:
testGradleVersion << [GRADLE_8_X]
}
def "warns and produces no dependency graph when enabled for older Gradle versions"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
def result = run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert !reportsDir.exists()
assert result.output.contains("::warning::Dependency Graph is not supported")
where:
testGradleVersion << NO_DEPENDENCY_GRAPH_VERSIONS
}
def "constructs unique job correlator for each build invocation"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
def reportFile1 = new File(reportsDir, "CORRELATOR-1.json")
def reportFile2 = new File(reportsDir, "CORRELATOR-2.json")
buildFile << """
task firstTask {
doLast {
println "First"
}
}
task secondTask {
doLast {
println "Second"
}
}
"""
when:
run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert reportFile.exists()
when:
run(['first'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert reportFile.exists()
assert reportFile1.exists()
when:
run(['second'], initScript, testGradleVersion.gradleVersion, [], envVars)
then:
assert reportFile.exists()
assert reportFile1.exists()
assert reportFile2.exists()
where:
testGradleVersion << DEPENDENCY_GRAPH_VERSIONS
}
def getEnvVars() {
return [
GITHUB_DEPENDENCY_GRAPH_ENABLED: "true",
GITHUB_JOB_CORRELATOR: "CORRELATOR",
GITHUB_JOB_ID: "1",
GITHUB_REF: "main",
GITHUB_SHA: "123456",
GITHUB_WORKSPACE: testProjectDir.absolutePath,
DEPENDENCY_GRAPH_REPORT_DIR: reportsDir.absolutePath,
GITHUB_OUTPUT: gitHubOutputFile.absolutePath
]
}
def getReportsDir() {
return new File(testProjectDir, 'build/reports/github-dependency-graph-snapshots')
}
def getReportFile() {
return new File(reportsDir, "CORRELATOR.json")
}
def getGitHubOutputFile() {
return new File(testProjectDir, "GITHUB_OUTPUT")
}
}

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.1.1") const gradleCurrent = path.resolve(gradleUserHome, "caches/8.2.1")
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

@@ -0,0 +1,34 @@
import * as dependencyGraph from '../../src/dependency-graph'
describe('dependency-graph', () => {
describe('constructs job correlator', () => {
it('removes commas from workflow name', () => {
const id = dependencyGraph.constructJobCorrelator('Workflow, with,commas', 'jobid', '{}')
expect(id).toBe('workflow_withcommas-jobid')
})
it('removes non word characters', () => {
const id = dependencyGraph.constructJobCorrelator('Workflow!_with()characters', 'job-*id', '{"foo": "bar!@#$%^&*("}')
expect(id).toBe('workflow_withcharacters-job-id-bar')
})
it('replaces spaces', () => {
const id = dependencyGraph.constructJobCorrelator('Workflow !_ with () characters, and spaces', 'job-*id', '{"foo": "bar!@#$%^&*("}')
expect(id).toBe('workflow___with_characters_and_spaces-job-id-bar')
})
it('without matrix', () => {
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', 'null')
expect(id).toBe('workflow-jobid')
})
it('with dashes in values', () => {
const id = dependencyGraph.constructJobCorrelator('workflow-name', 'job-id', '{"os": "ubuntu-latest"}')
expect(id).toBe('workflow-name-job-id-ubuntu-latest')
})
it('with single matrix value', () => {
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows"}')
expect(id).toBe('workflow-jobid-windows')
})
it('with composite matrix value', () => {
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows", "java-version": "21.1", "other": "Value, with COMMA"}')
expect(id).toBe('workflow-jobid-windows-211-value_with_comma')
})
})
})