Compare commits

...

44 Commits

Author SHA1 Message Date
Daz DeBoer
3f3947669a Rename action from "Gradle Command" to "Gradle Build Action" 2021-08-17 09:36:14 -06:00
dependabot[bot]
579711fd3c Bump path-parse from 1.0.6 to 1.0.7 (#65)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-16 15:52:54 -06:00
Daz DeBoer
7336529ec5 Build distribution 2021-08-07 16:13:35 -07:00
Daz DeBoer
88af98fab4 Fail if configuration-cache is enabled without dependencies cache
Fixes #61
2021-08-07 16:13:35 -07:00
Daz DeBoer
01bfa29846 Update metadata and docs for repository move/rename
Fixes #60
2021-08-07 16:13:35 -07:00
Paul Merlin
0206df026c Merge pull request #59 from eskatos/dd/v1-improved
Minor cleanups, simplifications and improvements
2021-07-27 08:45:59 +02:00
Paul Merlin
41aebc770d Fix typo in test workflow
Signed-off-by: Paul Merlin <paul@gradle.com>
2021-07-27 08:22:05 +02:00
Daz DeBoer
bc4d6bddd4 Rebuild index files 2021-07-26 15:45:00 -06:00
Daz DeBoer
1f57b4dd2d Re-add workflow jobs for dependencies and configuration caches 2021-07-26 15:45:00 -06:00
Daz DeBoer
02d4f46354 Use core functionality to access action inputs
- Specify default values in action.yaml definition where appropriate
- Replace custom methods with core functions:
  -  getInputBoolean() with core.getBooleanInput()
  - inputOrNull() with core.getInput()
  - inputArrayOrNull() with core.getMultilineInput()
- Remove github-utils.js
2021-07-26 14:54:59 -06:00
Daz DeBoer
b9684c0cf5 Prefer ‘release-candidate’ instead of ‘rc’
This makes the version alias match other places where we reference a release candidate version.
The 'rc' alias is still supported, but emits a deprecation warning.
2021-07-26 14:54:59 -06:00
Daz DeBoer
5423935c9b Deprecate the 'wrapper-directory' input and recommend 'gradle-executable' instead
Use of a wrapper in a non-standard directory is uncommon, and is effectively handled
by referencing the `gradlew` script as the `gradle-executable`.
2021-07-26 14:54:59 -06:00
Daz DeBoer
41ca2299a5 Ignore .tool-versions directory
This directory is created by the ASDF version manager (https://asdf-vm.com),
and can be used to control the version of nodejs/npm used to run.
2021-07-20 11:20:21 -06:00
Daz DeBoer
33e91b639d Cache Gradle distributions downloaded for a particular version (#58)
- Cache is separate from (but similar to) the wrapper distribution cache
- New 'distributions-cache-enabled' flag controls caching of all downloaded distributions
  (including wrapper distributions)
- Deprecated the 'wrapper-cache-enabled' flag for removal in v2
2021-07-08 12:22:48 -06:00
Daz DeBoer
e4ec586f46 Only cache the wrapper ZIP, not the exploded dir
Prior to this change, the wrapper cache contained both the downloaded zip
file as well as the exploded wrapper dir. Only the zip file is required,
as Gradle will automatically detect and unpack.
2021-07-08 08:01:44 -06:00
Daz DeBoer
15a8123fbc Validate presense of gradle wrapper to provide better feedback
- Provide a more useful error message when no Gradle wrapper can be located,
  and 'gradle-version' or 'gradle-executable' is not used.
- Add test for case where wrapper is missing.
  This isn't really a "test" per-se, but this failing build invocation makes it
  easy to verify the GitHub action behaviour when the build is misconfigured.
2021-07-08 08:01:44 -06:00
Daz DeBoer
f0c6ac01d3 Add test for gradle-executable parameter
Use matrix to allow different script suffix on windows
2021-07-06 13:29:55 -06:00
Daz DeBoer
63fea55da4 Add a very-limited ‘no-wrapper’ test Gradle build
Will use this for testing Gradle execution with different versions and mechanisms.
2021-07-06 13:29:55 -06:00
Daz DeBoer
26b92e3f5c Separate unit-test data from integ-test samples
- Upgraded `samples/basic` to use latest Gradle version.
2021-07-06 13:29:55 -06:00
Daz DeBoer
643092d2fc Ensure that test invocations are targeted at a specific use-case
- Remove the 'gradle --stop' step from the prod workflow.
  We either need to stop all instances started, or rely on GitHub to clean up processes on completion.
- Remove configuration-cache and dependencies-cache from basic tests. We will later need to add
  tests invocations specific for these features.
2021-07-06 13:29:55 -06:00
Daz DeBoer
18c8a679dc Look for gradle wrapper in build-root-directory by default
This removes the need to specify `wrapper-directory` when using a Gradle
project that is not located in the root of the workspace.

Fixes #44.
2021-07-06 09:56:27 -06:00
Paul Merlin
13d33a88ca Merge pull request #52 from eskatos/dd/update-versions
Update dependency versions
2021-07-06 11:47:55 +02:00
Daz DeBoer
738bda9866 Use built-in library functions in preference to custom implementations
- Use built-in `hashFiles` function included in '@actions/globv0.2.0'
- Use `downloadTool` and `extractZip` functions from '@actions/tool-cache'
2021-07-05 13:57:22 -06:00
Daz DeBoer
47c9af9d7d Rebuild outputs 2021-07-05 12:40:53 -06:00
Daz DeBoer
3fba6132b4 Update devDependencies versions 2021-07-05 12:40:37 -06:00
Daz DeBoer
127b9b6624 Update to latest lib dependencies 2021-07-05 12:40:16 -06:00
Daz DeBoer
8189d29e96 Run 'npm update'
Get latest versions of transitive deps.
2021-07-05 12:20:36 -06:00
Daz DeBoer
eb7aa853fa Run 'npm audit fix'
Updates transitive library versions to address known vulnerabilities
2021-07-05 12:05:56 -06:00
Tomaz Muraus
15bf8034d6 Fix typo, the directory which contains dependency locks is named
gradle/dependency-locks.
2020-12-22 12:13:55 +01:00
paul
6bf2690b23 Upgrade dependencies 2020-12-22 12:11:50 +01:00
Benedikt Ritter
ced6c34563 Add worknig example for build scan comment
Replaces the dummy example for how to automatically add a comment containing the build scan URL
with a working example using the [GitHub Script action](https://github.com/marketplace/actions/github-script#comment-on-an-issue).

See https://github.com/britter/maven-plugin-development/pull/56#issuecomment-708406163 for how it looks in action.
2020-10-14 15:57:13 +02:00
Paul Merlin
2efcc22ff5 Replace typed-rest-client with @actions/http-client 2020-09-13 14:17:37 +02:00
Paul Merlin
cb2742a00b Protect RC provisioning from network problems and add logging 2020-09-13 13:30:54 +02:00
Paul Merlin
c8c53f54bb Let CI exercises using latest Gradle RC 2020-09-13 13:25:31 +02:00
Paul Merlin
863daedf86 Bump test build wrapper 2020-09-13 13:23:48 +02:00
Paul Merlin
55871cbb47 Simplify build scan url extraction 2020-09-13 13:09:14 +02:00
Paul Merlin
e3d60b3873 Protect wrapper cache restore against tar errors 2020-09-13 13:06:00 +02:00
Paul Merlin
2dd6cc1801 Upgrade dependencies 2020-09-13 12:37:40 +02:00
Paul Merlin
f11e7d60d7 Short-circuit dependencies and configuration caching if cache dir already exists
This is relevant if you run this action several times in a single job.
This prevent doing unnecessary work starting with the second job using the action.
This prevent droping dependencies downloaded by the first job using the action.
This prevent Windows agents to fail unlinking already existing files.
2020-06-22 16:40:58 +02:00
Paul Merlin
7137b09ae2 Upgrade dependencies 2020-06-22 16:36:25 +02:00
Paul Merlin
053f389907 CI prod check workflow stops Gradle daemon at the end
to allow for dependency caching to work on windows
2020-06-15 20:08:27 +02:00
Paul Merlin
4f9b5202aa Faster CI 2020-06-15 20:03:30 +02:00
Paul Merlin
466a737d16 Only restore wrapper cache if dir doesn't exist 2020-06-15 19:33:04 +02:00
Paul Merlin
eb7eb78d95 Refine README 2020-06-15 16:50:15 +02:00
42 changed files with 3058 additions and 3044 deletions

View File

@@ -1,3 +1,4 @@
# make sure the build works and doesn't produce spurious changes
name: dev
on:
@@ -6,10 +7,7 @@ on:
jobs:
check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
@@ -17,19 +15,10 @@ jobs:
run: |
npm install
npm run all
- name: Test wrapper
uses: ./
with:
wrapper-directory: __tests__/data/basic
build-root-directory: __tests__/data/basic
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: test
- name: Test dist download
uses: ./
with:
gradle-version: 6.6-milestone-1
build-root-directory: __tests__/data/basic
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: test --configuration-cache
- name: Check for uncommitted changes
# Ensure no changes, but ignore node_modules dir since dev/fresh ci deps installed.
run: |
git diff --exit-code --stat -- . ':!node_modules' \
|| (echo "##[error] found changed files after build. please 'npm run all'" \
"and check in all changes" \
&& exit 1)

View File

@@ -2,13 +2,52 @@
name: prod
on:
pull_request:
push:
branches:
- master
- 'releases/*'
jobs:
check:
gradle-execution:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: windows-latest
script-suffix: '.bat'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Test use Gradle wrapper
uses: ./
with:
build-root-directory: __tests__/samples/basic
arguments: test
- name: Test use defined Gradle version
uses: ./
with:
gradle-version: 6.9
build-root-directory: __tests__/samples/no-wrapper
arguments: help
- name: Test use Gradle version alias
uses: ./
with:
gradle-version: release-candidate
build-root-directory: __tests__/samples/no-wrapper
arguments: help
- name: Test use defined Gradle executable
uses: ./
with:
gradle-executable: __tests__/samples/basic/gradlew${{ matrix.script-suffix }}
build-root-directory: __tests__/samples/no-wrapper
arguments: help
- name: Test custom wrapper location (deprecated)
uses: ./
with:
build-root-directory: __tests__/samples/no-wrapper
wrapper-directory: __tests__/samples/basic
arguments: help
dependencies-cache:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
@@ -16,19 +55,39 @@ jobs:
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Test wrapper
- name: Test dependencies-cache-enabled
uses: ./
with:
wrapper-directory: __tests__/data/basic
build-root-directory: __tests__/data/basic
build-root-directory: __tests__/samples/basic
arguments: test --no-daemon
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: test
- name: Test dist download
configuration-cache:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Test configuration-cache-enabled
uses: ./
with:
gradle-version: 6.6-milestone-1
build-root-directory: __tests__/data/basic
dependencies-cache-enabled: true
build-root-directory: __tests__/samples/basic
arguments: test --configuration-cache --no-daemon
configuration-cache-enabled: true
arguments: test --configuration-cache
dependencies-cache-enabled: true
# Configuration cache requires dependencies cache, since it assumes dependencies are already downloaded.
failures: # These build invocations are informational only, and are expected to fail
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Test wrapper missing
uses: ./
continue-on-error: true
with:
build-root-directory: __tests__/samples/no-wrapper
arguments: help

4
.gitignore vendored
View File

@@ -98,5 +98,9 @@ Thumbs.db
__tests__/runner/*
# lib/**/*
# IntelliJ IDEA config files
.idea/
*.iml
# ASDF tool configuration
.tool-versions

View File

@@ -1,12 +1,10 @@
# Execute Gradle commands in GitHub Actions workflows
# Execute Gradle builds in GitHub Actions workflows
This GitHub Action can be used to run arbitrary Gradle commands on any platform supported by GitHub Actions.
You might also be interested by the related [Gradle Plugin](https://github.com/eskatos/gradle-github-actions-plugin) that allows your build to easily get GitHub Actions environment and tag Gradle Build Scans accordingly.
This GitHub Action can be used to execute a Gradle build on any platform supported by GitHub Actions.
## Usage
The following workflow will run `./gradlew build` using the wrapper from the repository on ubuntu, macos and windows. The only prerequisite is to have Java installed, you can define the version you need to run the build using the `actions/setup-java` action.
The following workflow will run `./gradlew build` using the wrapper from the repository on ubuntu, macos and windows. The only prerequisite is to have Java installed: you define the version of Java you need to run the build using the `actions/setup-java` action.
```yaml
# .github/workflows/gradle-build-pr.yml
@@ -23,7 +21,7 @@ jobs:
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
arguments: build
```
@@ -47,7 +45,7 @@ See `gradle --help` for more information.
If you need to pass environment variables, simply use the GitHub Actions workflow syntax:
```yaml
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
env:
CI: true
```
@@ -55,31 +53,33 @@ If you need to pass environment variables, simply use the GitHub Actions workflo
## Run a build from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
build-root-directory: some/subdirectory
```
## Use a specific `gradle` executable
```yaml
- uses: gradle/gradle-build-action@v1
with:
gradle-executable: path/to/gradle
```
## Use a Gradle wrapper from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
wrapper-directory: path/to/wrapper-directory
gradle-executable: path/to/gradlew
```
## Use a specific `gradle` executable
```yaml
- uses: eskatos/gradle-command-action@v1
with:
gradle-executable: path/to/gradle
```
NOTE: The `wrapper-directory` input has been deprecated. Use `gradle-executable` instead.
## Setup and use a declared Gradle version
```yaml
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
gradle-version: 6.5
```
@@ -90,11 +90,11 @@ Moreover, you can use the following aliases:
| Alias | Selects |
| --- |---|
| `wrapper` | The Gradle wrapper's version (default, useful for matrix builds) |
| `current` | The current [stable release](https://gradle.org/install/) |
| `rc` | The current [release candidate](https://gradle.org/release-candidate/) if any, otherwise fallback to `current` |
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
| `release-nightly` | The latest [release nightly](https://gradle.org/release-nightly/), fails if none. |
| `wrapper` | The Gradle wrapper's version (default, useful for matrix builds) |
| `current` | The current [stable release](https://gradle.org/install/) |
| `release-candidate` | The current [release candidate](https://gradle.org/release-candidate/) if any, otherwise fallback to `current` |
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
| `release-nightly` | The latest [release nightly](https://gradle.org/release-nightly/), fails if none. |
This can be handy to, for example, automatically test your build with the next Gradle version once a release candidate is out:
@@ -112,9 +112,9 @@ jobs:
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
gradle-version: rc
gradle-version: release-candidate
arguments: build --dry-run # just test build configuration
```
@@ -122,36 +122,44 @@ jobs:
This action provides 3 levels of caching to help speed up your GitHub Actions:
- `wrapper` caches the local [wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) installation, saving time downloading and unpacking Gradle distributions ;
- `distributions` caches any downloaded Gradle zips, including any downloaded [wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) versions, saving time downloading Gradle distributions ;
- `dependencies` caches the [dependencies](https://docs.gradle.org/current/userguide/dependency_resolution.html#sub:cache_copy), saving time downloading dependencies ;
- `configuration` caches the [build configuration](https://docs.gradle.org/nightly/userguide/configuration_cache.html), saving time configuring the build.
Only the first one, caching the wrapper installation, is enabled by default.
Only the first one, caching downloaded distributions, is enabled by default.
Future versions of this action will enable all caching by default.
You can control which level is enabled as follows:
```yaml
wrapper-cache-enabled: true
distributions-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
```
The wrapper installation cache is simple and can't be configured further.
NOTE: The `wrapper-cache-enabled` flag has been deprecated, replaced by `distributions-cache-enabled` which enables caching for all downloaded distributions, including Gradle wrapper downloads.
The distributions cache is simple and can't be configured further.
The dependencies and configuration cache will compute a cache key in a best effort manner.
Keep reading to learn how to better control how they work.
Note that enabling configuration cache without thee dependencies cache is not permitted, since a hit in the configuration cache assumes that dependencies are already present in the local dependencies cache.
### Configuring the dependencies and configuration caches
Both the dependencies and configuration caches use the same default configuration:
They use the following inputs to calculate the cache key:
```text
**/*.gradle
**/*.gradle.kts
**/gradle.properties
gradle/**
```
This is a good enough approximation.
They restore cached state even if there isn't an exact match.
If the defaults don't suit your needs you can override them with the following inputs:
@@ -159,11 +167,11 @@ If the defaults don't suit your needs you can override them with the following i
```yaml
dependencies-cache-key: |
**/gradle.properties
gradle/dependency-locking/**
gradle/dependency-locks/**
dependencies-cache-exact: true
configuration-cache-key: |
**/gradle.properties
gradle/dependency-locking/**
gradle/dependency-locks/**
configuration-cache-exact: true
```
@@ -175,13 +183,13 @@ If you happen to use Gradle [dependency locking](https://docs.gradle.org/current
```yaml
dependencies-cache-enabled: true
dependencies-cache-key: gradle/dependency-locking/**
dependencies-cache-key: gradle/dependency-locks/**
dependencies-cache-exact: true
```
## Build scans
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-command-action` action will emit the link to the published build scan as an output named `build-scan-url`.
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-build-action` action will emit the link to the published build scan as an output named `build-scan-url`.
You can then use that link in subsequent actions of your workflow.
@@ -202,12 +210,20 @@ jobs:
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
- uses: gradle/gradle-build-action@v1
with:
arguments: build
id: gradle
- uses: example/action-that-comments-on-the-pr@v0
if: failure()
- name: "Comment build scan url"
uses: actions/github-script@v3
if: github.event_name == 'pull_request' && failure()
with:
comment: Build failed ${{ steps.gradle.outputs.build-scan-url }}
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.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 }}'
})
```

View File

@@ -6,22 +6,22 @@ describe('cache', () => {
it('from wrapper properties file', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFrom(
path.resolve(
'__tests__/data/basic/gradle/wrapper/gradle-wrapper.properties'
'__tests__/data/cache-wrapper-test/gradle-wrapper.properties'
)
)
expect(version).toBe('6.5-bin')
expect(version).toBe('6.6.1-bin')
})
it('for -bin dist', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6.1-bin.zip'
)
expect(version).toBe('6.5-bin')
expect(version).toBe('6.6.1-bin')
})
it('for -all dist', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-all.zip'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6.1-all.zip'
)
expect(version).toBe('6.5-all')
expect(version).toBe('6.6.1-all')
})
it('for milestone', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(

View File

@@ -5,34 +5,34 @@ describe('crypto-utils', () => {
describe('can hash', () => {
it('a directory', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/gradle')
path.resolve('__tests__/data/crypto-utils-test/gradle')
)
expect(hash).toBe(
process.platform === 'win32'
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
: '4ebb65b45e6f6796d5ec6ace96e9471cc6573d294c54f99c4920fe5328e75bab'
: '63b9f14f65d014e585099c9c274b9dcbddf5cfd1a8978e5a24efb89ff9304348'
)
})
it('a directory with a glob', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/'),
path.resolve('__tests__/data/crypto-utils-test/'),
['gradle/**']
)
expect(hash).toBe(
process.platform === 'win32'
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
: '4ebb65b45e6f6796d5ec6ace96e9471cc6573d294c54f99c4920fe5328e75bab'
: '63b9f14f65d014e585099c9c274b9dcbddf5cfd1a8978e5a24efb89ff9304348'
)
})
it('a directory with globs', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/'),
path.resolve('__tests__/data/crypto-utils-test/'),
['**/*.gradle', 'gradle/**']
)
expect(hash).toBe(
process.platform === 'win32'
? 'd9b66fded38f79f601ce745d64ed726a8df8c0b242b02bcd2c1d331f54742ad6'
: 'aa72a837158799fbadd1c4aff94fcc2b5bb9dc6ad8d12f6337d047d4b0c8f79e'
: 'f42cd10636f09799f4e01cc84e7ae906cc1d9140f1446f8dcd054d19cbc44c2b'
)
})
})

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

5
__tests__/samples/basic/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build

View File

@@ -0,0 +1,11 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('junit:junit:4.12')
}

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
__tests__/samples/basic/gradlew vendored Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# 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"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
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.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

104
__tests__/samples/basic/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,104 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1 @@
rootProject.name = 'basic'

View File

@@ -0,0 +1,10 @@
package basic;
import org.junit.Test;
public class BasicTest {
@Test
public void test() {
assert true;
}
}

View File

@@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

View File

@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build

View File

@@ -0,0 +1,3 @@
rootProject.name = 'no-wrapper'
println "Using Gradle version: ${gradle.gradleVersion}"

View File

@@ -1,6 +1,5 @@
name: "Gradle Command"
description: 'Execute Gradle Command Line'
author: 'Paul Merlin <paul@nospere.org>'
name: "Gradle Build Action"
description: 'Execute Gradle Build'
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
@@ -8,6 +7,7 @@ inputs:
wrapper-directory:
description: Path to the Gradle Wrapper directory
required: false
deprecationMessage: Use 'gradle-executable' to point to a gradlew[.bat] file in a non-default location
gradle-executable:
description: Path to the Gradle executable
required: false
@@ -20,27 +20,37 @@ inputs:
arguments:
description: Gradle command line arguments, see gradle --help
required: false
distributions-cache-enabled:
description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true'
required: false
default: true
wrapper-cache-enabled:
description: Whether caching wrapper installation is enabled or not, default to 'true'
required: false
default: true
deprecationMessage: Replaced by 'distributions-cache-enabled' which enables caching for all downloaded Gradle distributions
dependencies-cache-enabled:
description: Whether caching dependencies is enabled or not, default to 'false'
required: false
default: false
dependencies-cache-key:
description: Globs of files to hash in the build root directory, separated by new lines, use best-effort if unset
required: false
dependencies-cache-exact:
description: Whether to restore only if exact match, default to 'false'
required: false
default: false
configuration-cache-enabled:
description: Whether caching build configuration is enabled or not, default to 'false'
required: false
default: false
configuration-cache-key:
description: Globs of files to hash in the build root directory, separated by new lines, use best-effort if unset
required: false
configuration-cache-exact:
description: Whether to restore only if exact match, default to 'false'
required: false
default: false
outputs:
build-scan-url:

2
dist/main/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

5035
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
{
"name": "gradle-command-action",
"name": "gradle-build-action",
"version": "1.0.0",
"private": true,
"description": "Execute Gradle Command Line",
"description": "Execute Gradle Build",
"scripts": {
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
@@ -13,7 +13,7 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/eskatos/gradle-command-action.git"
"url": "git+https://github.com/gradle/gradle-build-action.git"
},
"keywords": [
"github",
@@ -24,30 +24,28 @@
"author": "Paul Merlin <paul@nosphere.org>",
"license": "MIT",
"dependencies": {
"@actions/cache": "0.2.1",
"@actions/core": "1.2.4",
"@actions/exec": "1.0.4",
"@actions/glob": "0.1.0",
"@actions/io": "1.0.2",
"@actions/tool-cache": "1.5.5",
"string-argv": "0.3.1",
"typed-rest-client": "1.7.3",
"unzipper": "0.10.11"
"@actions/cache": "1.0.7",
"@actions/core": "1.4.0",
"@actions/exec": "1.1.0",
"@actions/glob": "0.2.0",
"@actions/http-client": "1.0.11",
"@actions/tool-cache": "1.7.1",
"string-argv": "0.3.1"
},
"devDependencies": {
"@types/jest": "26.0.0",
"@types/node": "12.12.6",
"@types/unzipper": "0.10.3",
"@typescript-eslint/parser": "3.2.0",
"@types/jest": "26.0.23",
"@types/node": "14.17.3",
"@types/unzipper": "0.10.4",
"@typescript-eslint/parser": "4.28.2",
"@zeit/ncc": "0.22.3",
"eslint": "7.2.0",
"eslint-plugin-github": "4.0.1",
"eslint-plugin-jest": "23.13.2",
"jest": "26.0.1",
"jest-circus": "26.0.1",
"js-yaml": "3.14.0",
"prettier": "2.0.5",
"ts-jest": "26.1.0",
"typescript": "3.8.3"
"eslint": "7.30.0",
"eslint-plugin-github": "4.1.3",
"eslint-plugin-jest": "24.3.6",
"jest": "26.6.3",
"jest-circus": "26.6.3",
"js-yaml": "3.14.1",
"prettier": "2.3.2",
"ts-jest": "26.5.6",
"typescript": "4.3.5"
}
}

View File

@@ -4,10 +4,13 @@ import fs from 'fs'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from './github-utils'
import * as crypto from './crypto-utils'
import {inputCacheKeyGlobs, tryDeleteFiles} from './cache-dependencies'
import {
inputCacheKeyGlobs,
tryDeleteFiles,
isDependenciesCacheDisabled
} from './cache-dependencies'
const CONFIGURATION_CACHE_PATH = 'CONFIGURATION_CACHE_PATH'
const CONFIGURATION_CACHE_KEY = 'CONFIGURATION_CACHE_KEY'
@@ -18,10 +21,17 @@ export async function restoreCachedConfiguration(
): Promise<void> {
if (isConfigurationCacheDisabled()) return
if (isDependenciesCacheDisabled()) {
throw new Error(
`Must enable dependencies-cache when configuration-cache is enabled`
)
}
const cachePath = path.resolve(rootDir, '.gradle/configuration-cache')
if (fs.existsSync(cachePath)) return
core.saveState(CONFIGURATION_CACHE_PATH, cachePath)
const inputCacheExact = github.inputBoolean('configuration-cache-exact')
const inputCacheExact = core.getBooleanInput('configuration-cache-exact')
const cacheKeyGlobs = inputCacheKeyGlobs('configuration-cache-key')
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
@@ -92,5 +102,5 @@ export async function cacheConfiguration(): Promise<void> {
}
function isConfigurationCacheDisabled(): boolean {
return !github.inputBoolean('configuration-cache-enabled', false)
return !core.getBooleanInput('configuration-cache-enabled')
}

View File

@@ -5,7 +5,6 @@ import * as os from 'os'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from './github-utils'
import * as crypto from './crypto-utils'
const DEPENDENCIES_CACHE_PATH = 'DEPENDENCIES_CACHE_PATH'
@@ -18,9 +17,10 @@ export async function restoreCachedDependencies(
if (isDependenciesCacheDisabled()) return
const cachePath = path.resolve(os.homedir(), '.gradle/caches/modules-2')
if (fs.existsSync(cachePath)) return
core.saveState(DEPENDENCIES_CACHE_PATH, cachePath)
const inputCacheExact = github.inputBoolean('dependencies-cache-exact')
const inputCacheExact = core.getBooleanInput('dependencies-cache-exact')
const cacheKeyGlobs = inputCacheKeyGlobs('dependencies-cache-key')
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
@@ -102,13 +102,13 @@ export function tryDeleteFiles(filePaths: string[]): boolean {
return !failure
}
function isDependenciesCacheDisabled(): boolean {
return !github.inputBoolean('dependencies-cache-enabled', false)
export function isDependenciesCacheDisabled(): boolean {
return !core.getBooleanInput('dependencies-cache-enabled')
}
export function inputCacheKeyGlobs(input: string): string[] {
const inputValue = github.inputArrayOrNull(input)
return inputValue
const inputValue = core.getMultilineInput(input)
return inputValue.length > 0
? inputValue
: [
'**/*.gradle',

View File

@@ -5,11 +5,7 @@ import * as os from 'os'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from './github-utils'
const WRAPPER_CACHE_KEY = 'WRAPPER_CACHE_KEY'
const WRAPPER_CACHE_PATH = 'WRAPPER_CACHE_PATH'
const WRAPPER_CACHE_RESULT = 'WRAPPER_CACHE_RESULT'
const WRAPPER_SLUG = 'WRAPPER_SLUG'
export async function restoreCachedWrapperDist(
gradlewDirectory: string | null
@@ -17,58 +13,62 @@ export async function restoreCachedWrapperDist(
if (isWrapperCacheDisabled()) return
if (gradlewDirectory == null) return
const wrapperSlug = extractGradleWrapperSlugFrom(
path.join(
path.resolve(gradlewDirectory),
'gradle/wrapper/gradle-wrapper.properties'
)
const wrapperProperties = path.join(
path.resolve(gradlewDirectory),
'gradle/wrapper/gradle-wrapper.properties'
)
if (!wrapperSlug) return
const wrapperCacheKey = `wrapper-${wrapperSlug}`
const wrapperCachePath = path.join(
os.homedir(),
`.gradle/wrapper/dists/gradle-${wrapperSlug}`
)
core.saveState(WRAPPER_CACHE_KEY, wrapperCacheKey)
core.saveState(WRAPPER_CACHE_PATH, wrapperCachePath)
const restoredKey = await cache.restoreCache(
[wrapperCachePath],
wrapperCacheKey
)
if (!restoredKey) {
core.info(
'Wrapper installation cache not found, expect a Gradle distribution download.'
const wrapperSlug = extractGradleWrapperSlugFrom(wrapperProperties)
if (!wrapperSlug) {
core.warning(
`Could not calculate wrapper version from ${wrapperProperties}`
)
return
}
core.saveState(WRAPPER_CACHE_RESULT, restoredKey)
core.info(`Wrapper installation restored from cache key: ${restoredKey}`)
return
const wrapperDir = getWrapperDir(wrapperSlug)
const cacheKey = getCacheKey(wrapperSlug)
const cachePath = getCachePath(wrapperSlug)
// Check if the wrapper has already been downloaded to Gradle User Home
if (fs.existsSync(wrapperDir)) return
try {
const restoredKey = await cache.restoreCache([cachePath], cacheKey)
if (restoredKey) {
core.info(
`Wrapper installation restored from cache key: ${restoredKey}`
)
} else {
core.info(
`Wrapper installation cache not found. Will download and cache with key: ${cacheKey}.`
)
// Save the slug to trigger caching of the downloaded wrapper
core.saveState(WRAPPER_SLUG, wrapperSlug)
}
} catch (error) {
core.info(
`Wrapper installation cache restore failed for key: ${cacheKey}.\n ${error}`
)
}
}
export async function cacheWrapperDist(): Promise<void> {
if (isWrapperCacheDisabled()) return
const cacheKey = core.getState(WRAPPER_CACHE_KEY)
const cachePath = core.getState(WRAPPER_CACHE_PATH)
const cacheResult = core.getState(WRAPPER_CACHE_RESULT)
const wrapperSlug = core.getState(WRAPPER_SLUG)
if (!wrapperSlug) return
if (!cachePath || !fs.existsSync(cachePath)) {
core.debug('No wrapper installation to cache.')
const wrapperDir = getWrapperDir(wrapperSlug)
const cacheKey = getCacheKey(wrapperSlug)
const cachePath = getCachePath(wrapperSlug)
if (!fs.existsSync(wrapperDir)) {
core.warning(`No wrapper installation to cache at ${wrapperDir}`)
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Wrapper installation cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
core.info(`Will cache wrapper zip ${cachePath} with key ${cacheKey}`)
try {
await cache.saveCache([cachePath], cacheKey)
@@ -105,5 +105,28 @@ export function extractGradleWrapperSlugFromDistUri(
}
function isWrapperCacheDisabled(): boolean {
return !github.inputBoolean('wrapper-cache-enabled', true)
// Check if either 'distributions' or 'wrapper' cache has been disabled
const wrapperCacheEnabled = core.getBooleanInput('wrapper-cache-enabled')
const distributionsCacheEnabled = core.getBooleanInput(
'distributions-cache-enabled'
)
return !wrapperCacheEnabled || !distributionsCacheEnabled
}
function getCacheKey(wrapperSlug: string): string {
return `wrapper-v1-${wrapperSlug}`
}
function getWrapperDir(wrapperSlug: string): string {
return path.resolve(
os.homedir(),
`.gradle/wrapper/dists/gradle-${wrapperSlug}`
)
}
function getCachePath(wrapperSlug: string): string {
return path.resolve(
os.homedir(),
`.gradle/wrapper/dists/gradle-${wrapperSlug}/*/gradle-${wrapperSlug}.zip`
)
}

View File

@@ -1,44 +1,13 @@
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as path from 'path'
import * as stream from 'stream'
import * as util from 'util'
import * as glob from '@actions/glob'
export async function hashFiles(
baseDir: string,
globs: string[] = ['**'],
patterns: string[] = ['**'],
followSymbolicLinks = false
): Promise<string | null> {
let hasMatch = false
type FileHashes = Record<string, Buffer>
const hashes: FileHashes = {}
for await (const globPattern of globs) {
const globMatch = `${baseDir}${path.sep}${globPattern}`
const globber = await glob.create(globMatch, {followSymbolicLinks})
for await (const file of globber.globGenerator()) {
// console.log(file)
if (!file.startsWith(`${baseDir}${path.sep}`)) {
// console.log(`Ignore '${file}' since it is not under '${baseDir}'.`)
continue
}
if (fs.statSync(file).isDirectory()) {
// console.log(`Skip directory '${file}'.`)
continue
}
const hash = crypto.createHash('sha256')
const pipeline = util.promisify(stream.pipeline)
await pipeline(fs.createReadStream(file), hash)
hashes[path.relative(baseDir, file)] = hash.digest()
hasMatch = true
}
}
if (!hasMatch) return null
const result = crypto.createHash('sha256')
for (const file of Object.keys(hashes).sort()) {
result.update(hashes[file])
}
result.end()
return result.digest('hex')
const combinedPatterns = patterns
.map(pattern => `${baseDir}${path.sep}${pattern}`)
.join('\n')
return glob.hashFiles(combinedPatterns, {followSymbolicLinks})
}

View File

@@ -18,12 +18,9 @@ export async function execute(
ignoreReturnCode: true,
listeners: {
stdline: (line: string) => {
if (line.startsWith('Publishing build scan...')) {
if (line.includes('Publishing build scan...')) {
publishing = true
}
if (publishing && line.length === 0) {
publishing = false
}
if (publishing && line.startsWith('http')) {
buildScanUrl = line.trim()
publishing = false

View File

@@ -1,24 +0,0 @@
import * as core from '@actions/core'
export function inputOrNull(name: string): string | null {
const inputString = core.getInput(name, {required: false})
if (inputString.length === 0) {
return null
}
return inputString
}
export function inputArrayOrNull(name: string): string[] | null {
const string = inputOrNull(name)
if (!string) return null
return string
.split('\n')
.map(s => s.trim())
.filter(s => s !== '')
}
export function inputBoolean(name: string, defaultValue = false): boolean {
const string = inputOrNull(name)
if (!string) return defaultValue
return string === 'true'
}

View File

@@ -1,3 +1,6 @@
import * as path from 'path'
import fs from 'fs'
const IS_WINDOWS = process.platform === 'win32'
export function wrapperFilename(): string {
@@ -7,3 +10,15 @@ export function wrapperFilename(): string {
export function installScriptFilename(): string {
return IS_WINDOWS ? 'gradle.bat' : 'gradle'
}
export function validateGradleWrapper(gradlewDirectory: string): void {
const wrapperProperties = path.resolve(
gradlewDirectory,
'gradle/wrapper/gradle-wrapper.properties'
)
if (!fs.existsSync(wrapperProperties)) {
throw new Error(
`Cannot locate a Gradle wrapper properties file at '${wrapperProperties}'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.`
)
}
}

View File

@@ -2,7 +2,6 @@ import * as core from '@actions/core'
import * as path from 'path'
import {parseArgsStringToArgv} from 'string-argv'
import * as github from './github-utils'
import * as cacheWrapper from './cache-wrapper'
import * as execution from './execution'
import * as gradlew from './gradlew'
@@ -11,11 +10,15 @@ import * as provision from './provision'
// Invoked by GitHub Actions
export async function run(): Promise<void> {
try {
const baseDirectory = process.env[`GITHUB_WORKSPACE`] || ''
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
const result = await execution.execute(
await resolveGradleExecutable(baseDirectory),
resolveBuildRootDirectory(baseDirectory),
await resolveGradleExecutable(
workspaceDirectory,
buildRootDirectory
),
buildRootDirectory,
parseCommandLineArguments()
)
@@ -33,43 +36,47 @@ export async function run(): Promise<void> {
run()
async function resolveGradleExecutable(baseDirectory: string): Promise<string> {
const gradleVersion = github.inputOrNull('gradle-version')
if (gradleVersion !== null && gradleVersion !== 'wrapper') {
async function resolveGradleExecutable(
workspaceDirectory: string,
buildRootDirectory: string
): Promise<string> {
const gradleVersion = core.getInput('gradle-version')
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
return path.resolve(await provision.gradleVersion(gradleVersion))
}
const gradleExecutable = github.inputOrNull('gradle-executable')
if (gradleExecutable !== null) {
const gradleExecutable = core.getInput('gradle-executable')
if (gradleExecutable !== '') {
if (gradleExecutable.endsWith(gradlew.wrapperFilename())) {
await cacheWrapper.restoreCachedWrapperDist(
path.resolve(gradleExecutable, '..')
)
}
return path.resolve(baseDirectory, gradleExecutable)
return path.resolve(workspaceDirectory, gradleExecutable)
}
const wrapperDirectory = github.inputOrNull('wrapper-directory')
const wrapperDirectory = core.getInput('wrapper-directory')
const gradlewDirectory =
wrapperDirectory !== null
? path.join(baseDirectory, wrapperDirectory)
: baseDirectory
wrapperDirectory !== ''
? path.resolve(workspaceDirectory, wrapperDirectory)
: buildRootDirectory
gradlew.validateGradleWrapper(gradlewDirectory)
await cacheWrapper.restoreCachedWrapperDist(gradlewDirectory)
return path.resolve(gradlewDirectory, gradlew.wrapperFilename())
}
function resolveBuildRootDirectory(baseDirectory: string): string {
const buildRootDirectory = github.inputOrNull('build-root-directory')
const buildRootDirectory = core.getInput('build-root-directory')
const resolvedBuildRootDirectory =
buildRootDirectory === null
buildRootDirectory === ''
? path.resolve(baseDirectory)
: path.resolve(baseDirectory, buildRootDirectory)
return resolvedBuildRootDirectory
}
function parseCommandLineArguments(): string[] {
const input = github.inputOrNull('arguments')
return input === null ? [] : parseArgsStringToArgv(input)
const input = core.getInput('arguments')
return parseArgsStringToArgv(input)
}

View File

@@ -1,15 +1,13 @@
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import * as httpm from 'typed-rest-client/HttpClient'
import * as unzip from 'unzipper'
import * as httpm from '@actions/http-client'
import * as core from '@actions/core'
import * as io from '@actions/io'
import * as cache from '@actions/cache'
import * as toolCache from '@actions/tool-cache'
import * as gradlew from './gradlew'
const httpc = new httpm.HttpClient('eskatos/gradle-command-action')
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
/**
@@ -20,6 +18,11 @@ export async function gradleVersion(version: string): Promise<string> {
case 'current':
return gradleCurrent()
case 'rc':
core.warning(
`Specifying gradle-version 'rc' has been deprecated. Use 'release-candidate' instead.`
)
return gradleReleaseCandidate()
case 'release-candidate':
return gradleReleaseCandidate()
case 'nightly':
return gradleNightly()
@@ -34,16 +37,17 @@ async function gradleCurrent(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/current`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
return provisionGradle(versionInfo)
}
async function gradleReleaseCandidate(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/release-candidate`
)
if (versionInfo) {
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
if (versionInfo && versionInfo.version && versionInfo.downloadUrl) {
return provisionGradle(versionInfo)
}
core.info('No current release-candidate found, will fallback to current')
return gradleCurrent()
}
@@ -51,14 +55,14 @@ async function gradleNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/nightly`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
return provisionGradle(versionInfo)
}
async function gradleReleaseNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/release-nightly`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
return provisionGradle(versionInfo)
}
async function gradle(version: string): Promise<string> {
@@ -66,7 +70,7 @@ async function gradle(version: string): Promise<string> {
if (!versionInfo) {
throw new Error(`Gradle version ${version} does not exists`)
}
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
return provisionGradle(versionInfo)
}
async function gradleVersionDeclaration(
@@ -86,42 +90,79 @@ async function findGradleVersionDeclaration(
})
}
async function provisionGradle(version: string, url: string): Promise<string> {
const cachedInstall: string = toolCache.find('gradle', version)
if (cachedInstall.length > 0) {
const cachedExecutable = executableFrom(cachedInstall)
core.info(`Provisioned Gradle executable ${cachedExecutable}`)
return cachedExecutable
async function provisionGradle(
versionInfo: GradleVersionInfo
): Promise<string> {
const installsDir = path.join(os.homedir(), 'gradle-installations/installs')
const installDir = path.join(installsDir, `gradle-${versionInfo.version}`)
if (fs.existsSync(installDir)) {
core.info(`Gradle installation already exists at ${installDir}`)
return executableFrom(installDir)
}
const home = os.homedir()
const tmpdir = path.join(home, 'gradle-provision-tmpdir')
const downloadsDir = path.join(tmpdir, 'downloads')
const installsDir = path.join(tmpdir, 'installs')
await io.mkdirP(downloadsDir)
await io.mkdirP(installsDir)
core.info(`Downloading ${url}`)
const downloadPath = path.join(downloadsDir, `gradle-${version}-bin.zip`)
await httpDownload(url, downloadPath)
core.info(
`Downloaded at ${downloadPath}, size ${fs.statSync(downloadPath).size}`
)
await extractZip(downloadPath, installsDir)
const installDir = path.join(installsDir, `gradle-${version}`)
core.info(`Extracted in ${installDir}`)
const downloadPath = await downloadAndCacheGradleDistribution(versionInfo)
await toolCache.extractZip(downloadPath, installsDir)
core.info(`Extracted Gradle ${versionInfo.version} to ${installDir}`)
const executable = executableFrom(installDir)
fs.chmodSync(executable, '755')
core.info(`Provisioned Gradle executable ${executable}`)
toolCache.cacheDir(installDir, 'gradle', version)
return executable
}
async function downloadAndCacheGradleDistribution(
versionInfo: GradleVersionInfo
): Promise<string> {
const downloadPath = path.join(
os.homedir(),
`gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`
)
if (isDistributionsCacheDisabled()) {
await downloadGradleDistribution(versionInfo, downloadPath)
return downloadPath
}
const cacheKey = `gradle-${versionInfo.version}`
const restoreKey = await cache.restoreCache([downloadPath], cacheKey)
if (restoreKey) {
core.info(
`Restored Gradle distribution ${cacheKey} from cache to ${downloadPath}`
)
} else {
core.info(
`Gradle distribution ${versionInfo.version} not found in cache. Will download.`
)
await downloadGradleDistribution(versionInfo, downloadPath)
try {
await cache.saveCache([downloadPath], cacheKey)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message)
} else {
core.info(`[warning] ${error.message}`)
}
}
}
return downloadPath
}
async function downloadGradleDistribution(
versionInfo: GradleVersionInfo,
downloadPath: string
): Promise<void> {
await toolCache.downloadTool(versionInfo.downloadUrl, downloadPath)
core.info(
`Downloaded ${versionInfo.downloadUrl} to ${downloadPath} (size ${
fs.statSync(downloadPath).size
})`
)
}
function executableFrom(installDir: string): string {
return path.join(installDir, 'bin', `${gradlew.installScriptFilename()}`)
}
@@ -137,36 +178,13 @@ async function httpGetGradleVersions(
}
async function httpGetString(url: string): Promise<string> {
const response = await httpc.get(url)
const httpClient = new httpm.HttpClient('gradle/gradle-build-action')
const response = await httpClient.get(url)
return response.readBody()
}
async function httpDownload(url: string, localPath: string): Promise<void> {
const response = await httpc.get(url)
return new Promise<void>(function (resolve, reject) {
const writeStream = fs.createWriteStream(localPath)
response.message
.pipe(writeStream)
.on('close', () => {
resolve()
})
.on('error', err => {
reject(err)
})
})
}
async function extractZip(zip: string, destination: string): Promise<void> {
return new Promise<void>(function (resolve, reject) {
fs.createReadStream(zip)
.pipe(unzip.Extract({path: destination}))
.on('close', () => {
resolve()
})
.on('error', err => {
reject(err)
})
})
function isDistributionsCacheDisabled(): boolean {
return !core.getBooleanInput('distributions-cache-enabled')
}
interface GradleVersionInfo {