Compare commits

..

101 Commits

Author SHA1 Message Date
Paul Merlin c6b57b9c8c Merge branch 'master' into releases/v1 2020-06-22 16:45:23 +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 791b98c565 Merge branch 'master' into releases/v1 2020-06-15 19:35:42 +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
Paul Merlin 27da3e28b3 Merge branch 'master' into releases/v1 2020-06-15 16:40:55 +02:00
Paul Merlin 682d7347f7 Optional dependencies cache
and bonus configuration cache

Merge branch 'eskatos/caching'
2020-06-15 16:36:19 +02:00
Paul Merlin 3c43b6525f Add some documentation around caching 2020-06-15 16:23:01 +02:00
Paul Merlin aefd8348d2 Enable configuration cache on CI 2020-06-15 16:03:04 +02:00
Paul Merlin f2de61db4e Enable configuration cache on CI 2020-06-15 15:58:50 +02:00
Paul Merlin 4c7d97cca4 Add caching of Gradle build configuration cache 2020-06-15 15:58:20 +02:00
Paul Merlin 806543fb3a Enable dependencies cache on CI 2020-06-15 15:57:47 +02:00
Paul Merlin 2afa86ca9f Disable dependencies cache by default 2020-06-15 15:57:09 +02:00
Paul Merlin ae50675399 Better warning message 2020-06-15 15:43:21 +02:00
Paul Merlin d7a54a26c7 Don't drop gc.properties in dependencies cache
because it would disable Gradle cache cleanup
2020-06-15 15:41:53 +02:00
Paul Merlin 02a8a21e55 Add input to disable wrapper caching 2020-06-15 15:41:09 +02:00
Paul Merlin 3abad5567a Add input to disable dependencies caching altogether 2020-06-15 14:32:54 +02:00
Paul Merlin 7c8cc1a9ef Fix typo 2020-06-15 14:28:57 +02:00
Paul Merlin 355e9c1f86 Try delete dependencies lock files and disable caching if not possible 2020-06-15 14:22:41 +02:00
Paul Merlin 26dd4cb9bb Make file hashing more robust 2020-06-15 14:09:44 +02:00
Paul Merlin 317ca35dca Refine dependencies caching 2020-06-15 13:16:51 +02:00
Paul Merlin 053762c1c1 Add input to make the dependencies caching strict 2020-06-15 13:05:36 +02:00
Paul Merlin 95e20daa83 Automatic caching of dependencies
in a best effort manner by default
allowing to specify files to hash for computing the cache key
2020-06-15 13:04:42 +02:00
Paul Merlin fcc1683d01 Extract github actions utils 2020-06-14 19:05:03 +02:00
Paul Merlin 059f2e7791 Rename cache.ts to cache-wrapper.ts 2020-06-14 19:04:18 +02:00
Paul Merlin 692fda9de7 Cache wrapper install when gradle-executable points to a wrapper 2020-06-14 18:01:54 +02:00
Paul Merlin e8885a31b8 Refine README 2020-06-14 12:57:10 +02:00
Paul Merlin e220e54c83 Merge branch 'master' into releases/v1 2020-06-14 12:41:26 +02:00
Paul Merlin 12e24e843d Fix for Windows
Merge branch 'eskatos/fix-windows'
2020-06-14 12:39:47 +02:00
Paul Merlin b35e929b1d Simplify CI 2020-06-14 12:36:06 +02:00
Paul Merlin c839ac993c Locate user home in an OS agnostic way 2020-06-14 12:28:17 +02:00
Paul Merlin 83e6d042d7 Run CI on linux, macos and windows 2020-06-14 12:22:21 +02:00
Paul Merlin 720051268d Cleanup 2020-06-13 16:37:23 +02:00
Paul Merlin 36d51a403a Merge branch 'master' into releases/v1 2020-06-13 16:33:57 +02:00
Paul Merlin b995a7b937 Merge pull request #19 from eskatos/eskatos/june
Automatically cache wrapper installation
2020-06-13 16:31:47 +02:00
Paul Merlin 1c1db193aa Cache wrapper installation 2020-06-13 16:15:53 +02:00
Paul Merlin 9675f09de6 Compute wrapper cache key 2020-06-13 15:51:58 +02:00
Paul Merlin 392bcac1c1 Fix state 2020-06-13 15:03:30 +02:00
Paul Merlin a2ba1beedb Debugging 2020-06-13 15:01:08 +02:00
Paul Merlin 42e2fed267 Cache wrapper dist, step 1 2020-06-13 14:48:54 +02:00
Paul Merlin 8e2fd532f1 Fix dist download 2020-06-13 14:37:12 +02:00
Paul Merlin 2bf5eec3b6 Test dist download on CI 2020-06-13 14:33:32 +02:00
Paul Merlin 43efc20423 Run lint on CI 2020-06-13 14:33:04 +02:00
Paul Merlin 4a9a0a05a3 Lint 3 2020-06-13 14:30:57 +02:00
Paul Merlin 1647b85e82 Lint 2 2020-06-13 14:21:54 +02:00
Paul Merlin 6cee865aea Lint 2020-06-13 13:58:25 +02:00
Paul Merlin 5c61ab77ec Add back CI check for uncommited changes 2020-06-13 13:46:53 +02:00
Paul Merlin a31de8476d Format 2020-06-13 13:44:30 +02:00
Paul Merlin b2c379621c Add @action/cache 2020-06-13 13:42:27 +02:00
Paul Merlin 04a5ee4df2 Cleanup 2020-06-13 13:40:38 +02:00
Paul Merlin a188e7cd61 Debug logging 2020-06-13 13:36:11 +02:00
Paul Merlin e0644c97f9 Split action, step 2 2020-06-13 13:34:07 +02:00
Paul Merlin 9cc76cdea7 Split action, step 1 2020-06-13 13:30:20 +02:00
Paul Merlin b55d63f1f8 Refine CI workflows 2020-06-13 13:17:04 +02:00
Paul Merlin 8f6be44bf5 Split dev/prod CI workflows 2020-06-13 13:14:52 +02:00
Paul Merlin 469bf6123e Fix CI 2020-06-13 13:10:37 +02:00
Paul Merlin 9cbb22e130 Test something on CI 2020-06-13 13:09:06 +02:00
Paul Merlin 4c65920ab9 Fix build 2020-06-13 13:03:18 +02:00
Paul Merlin bad0f7d376 Fix build 2020-06-13 13:00:27 +02:00
Paul Merlin ab09ae8fad Refine CI 2020-06-13 12:48:35 +02:00
Paul Merlin 2f66fb5679 Add basic test Gradle build 2020-06-13 12:47:27 +02:00
Paul Merlin 1a6a8efda2 Refine CI 2020-06-13 12:47:09 +02:00
Paul Merlin e5b01ed062 Add more npm scripts 2020-06-13 12:47:01 +02:00
Paul Merlin 3d5e31b7a4 Upgrade dependencies 2020-06-13 12:46:47 +02:00
Paul Merlin 4336c6b886 Add various js build configs 2020-06-13 12:46:29 +02:00
Paul Merlin f25026ba74 Refine README 2020-06-13 12:45:21 +02:00
Paul Merlin 9f5ce3593a Fix typo 2020-04-18 17:10:08 +02:00
Ivan Shcherbak a5009d1aec Fix typo
Get an error from Github: `pull-request is not a valid event name`

https://help.github.com/en/actions/reference/events-that-trigger-workflows#example-using-a-list-of-events
2020-04-18 17:09:21 +02:00
Frieder Bluemle ae5079ecac Fix GitHub spelling 2020-03-17 22:36:04 +01:00
Paul Merlin 38fdc3f684 Upgrade dependencies 2020-01-12 11:39:57 +01:00
Paul Merlin d0c5f7955e build 2019-12-09 15:22:02 +01:00
Paul Merlin a2ba194e38 Merge branch 'master' into releases/v1 2019-12-09 15:20:11 +01:00
Paul Merlin 0821518fd9 Merge pull request #6 from musketyr/patch-1
ignore version called "wrapper"
2019-12-09 15:18:28 +01:00
Vladimir Orany c8b76ea3f7 Update README.md 2019-12-09 10:46:30 +01:00
Vladimir Orany bf26498bc4 ignore version called "wrapper"
fixes #5
2019-12-09 10:44:21 +01:00
Paul Merlin 064f85c156 build 2019-10-28 13:31:49 +01:00
Paul Merlin 580b26a94c Merge branch 'master' into releases/v1 2019-10-28 13:30:49 +01:00
Paul Merlin 15e064da79 Add missing await 2019-10-28 13:30:27 +01:00
Paul Merlin c61d0fe2b5 Merge branch 'master' into releases/v1 2019-10-28 13:27:16 +01:00
Paul Merlin c5e1979a6b Fix relative paths issues when using build-root-directory 2019-10-28 13:26:37 +01:00
Paul Merlin dc882d2669 fix yaml comments in README's samples 2019-09-23 13:00:12 +02:00
Paul Merlin f9f0422c72 add example of using the build-scan-url output in README 2019-09-23 12:56:08 +02:00
Paul Merlin 6170f06e8d build 2019-09-23 12:20:06 +02:00
Paul Merlin e561eefa28 Merge branch 'master' into releases/v1 2019-09-23 12:17:48 +02:00
Paul Merlin 38eaee068d polish src/provision.ts 2019-09-23 12:12:03 +02:00
Paul Merlin 0a56b592f2 capture build scan url on failed build 2019-09-23 12:11:18 +02:00
Paul Merlin 091093ee61 polish src/gradlew.ts 2019-09-23 12:10:49 +02:00
Paul Merlin 7a4f128c22 refine tsconfig 2019-09-23 12:10:32 +02:00
Paul Merlin f943246fd9 refine readme 2019-09-23 12:10:22 +02:00
Paul Merlin 8337949d80 better .gitignore 2019-09-22 11:06:17 +02:00
Paul Merlin 76166f0035 refine readme 2019-09-21 21:02:16 +02:00
Paul Merlin a9718db8ba add code of conduct 2019-09-21 20:57:04 +02:00
Paul Merlin 2d5ca45eab publishing v1 of action 2019-09-21 16:11:55 +02:00
Paul Merlin 91baa89272 fix package.json 2019-09-21 16:09:41 +02:00
Paul Merlin 6f837e9062 Minor README edits 2019-09-21 16:04:03 +02:00
Paul Merlin bc921df1ec Initial impl 2019-09-21 16:01:53 +02:00
Paul Merlin f4a8f7a81b minor edits & build 2019-09-20 23:23:07 +02:00
Paul Merlin 8ba9907b46 Initial commit 2019-09-20 23:06:59 +02:00
45 changed files with 9126 additions and 348 deletions
+3
View File
@@ -0,0 +1,3 @@
dist/
lib/
node_modules/
+52
View File
@@ -0,0 +1,52 @@
{
"plugins": ["jest", "@typescript-eslint"],
"extends": ["plugin:github/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"camelcase": "off",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": ["error", {"ignoreStringArrays": true}],
"@typescript-eslint/restrict-plus-operands": "error",
"semi": "off",
"@typescript-eslint/semi": ["error", "never"],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true,
"jest/globals": true
}
}
@@ -1,30 +0,0 @@
name: Test dependency-submission save
on:
workflow_dispatch:
push:
permissions:
contents: read
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
dependency-submission-save:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Checkout gradle-build-action for samples
uses: actions/checkout@v4
with:
repository: gradle/gradle-build-action
path: gradle-build-action
- name: Generate and save dependency graph
uses: ./dependency-submission
with:
build-root-directory: gradle-build-action/.github/workflow-samples/groovy-dsl
dependency-graph-action: generate-and-save
env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
@@ -1,23 +0,0 @@
name: Test dependency-submission submit
on:
workflow_run:
workflows: ['Test dependency-submission save']
types: [completed]
permissions:
contents: write
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
dependency-submission-submit:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Download and submit dependency graph
uses: ./dependency-submission
with:
dependency-graph-action: retrieve-and-submit
@@ -1,29 +0,0 @@
name: Test dependency-submission
on:
workflow_dispatch:
push:
permissions:
contents: write
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
test-dependency-submission:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Checkout gradle-build-action for samples
uses: actions/checkout@v4
with:
repository: gradle/gradle-build-action
path: gradle-build-action
- name: Generate and submit dependencies
uses: ./dependency-submission
with:
build-root-directory: gradle-build-action/.github/workflow-samples/groovy-dsl
env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
+24
View File
@@ -0,0 +1,24 @@
# make sure the build works and doesn't produce spurious changes
name: dev
on:
pull_request:
push:
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Build
run: |
npm install
npm run all
- 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)
+40
View File
@@ -0,0 +1,40 @@
# make sure the action works on a clean machine without building
name: prod
on:
pull_request:
push:
jobs:
check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
- 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: Stop Gradle daemon
uses: ./
with:
gradle-version: 6.6-milestone-1
build-root-directory: __tests__/data/basic
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: --stop
-25
View File
@@ -1,25 +0,0 @@
name: Test setup-gradle
on:
workflow_dispatch:
push:
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
test-setup-gradle:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Checkout gradle-build-action for samples
uses: actions/checkout@v4
with:
repository: gradle/gradle-build-action
path: gradle-build-action
- name: Setup Gradle
uses: ./setup-gradle
- name: Build groovy-dsl project
working-directory: gradle-build-action/.github/workflow-samples/groovy-dsl
run: ./gradlew assemble
+102
View File
@@ -0,0 +1,102 @@
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
__tests__/runner/*
# lib/**/*
.idea/
*.iml
+3
View File
@@ -0,0 +1,3 @@
dist/
lib/
node_modules/
+11
View File
@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}
+76
View File
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at paul@nosphere.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 GitHub, Inc. and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+198 -39
View File
@@ -1,58 +1,217 @@
# GitHub Actions for Gradle builds
# Execute Gradle commands in GitHub Actions workflows
This repository contains a set of GitHub Actions that are useful for building Gradle projects on GitHub.
This GitHub Action can be used to run arbitrary Gradle commands on any platform supported by GitHub Actions.
## `gradle/actions/setup-gradle`
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.
A simple wrapper around `gradle/gradle-build-action`, removing the deprecated `arguments` parameter (and thus removing the ability to _execute_ gradle).
The intention is to eventually deprecate `gradle-build-action` with this being the replacement.
## Usage
### Example 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.
```yaml
name: Build
on:
workflow_dispatch:
push:
# .github/workflows/gradle-build-pr.yml
name: Run Gradle on PRs
on: pull_request
jobs:
build:
runs-on: ubuntu-latest
gradle:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v0
- name: Build with Gradle
run: ./gradlew build
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
with:
arguments: build
```
## `gradle/actions/dependency-submission`
## Gradle arguments
Generates and submits a dependency graph for a Gradle project. This action is designed to be used in a standalone workflow.
The intention is to provide a simple, standardised way to enable Dependency Graph support for Gradle repositories,
with a long-term goal of having this functionality enabled by default for Gradle projects on GitHub.
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
### Example usage
Here are some valid examples:
```yaml
name: Dependency Submission
arguments: build
arguments: check --scan
arguments: some arbitrary tasks
arguments: build -PgradleProperty=foo
arguments: build -DsystemProperty=bar
....
```
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
env:
CI: true
```
## Run a build from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
with:
build-root-directory: some/subdirectory
```
## Use a Gradle wrapper from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
with:
wrapper-directory: path/to/wrapper-directory
```
## Use a specific `gradle` executable
```yaml
- uses: eskatos/gradle-command-action@v1
with:
gradle-executable: path/to/gradle
```
## Setup and use a declared Gradle version
```yaml
- uses: eskatos/gradle-command-action@v1
with:
gradle-version: 6.5
```
`gradle-version` can be set to any valid Gradle version.
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. |
This can be handy to, for example, automatically test your build with the next Gradle version once a release candidate is out:
```yaml
# .github/workflows/test-gradle-rc.yml
name: Test latest Gradle RC
on:
workflow_dispatch:
push:
branches:
- main
permissions:
contents: write
schedule:
- cron: 0 0 * * * # daily
jobs:
dependency-submission:
gradle-rc:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v0
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
with:
gradle-version: rc
arguments: build --dry-run # just test build configuration
```
## Caching
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 ;
- `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.
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
dependencies-cache-enabled: true
configuration-cache-enabled: true
```
The wrapper installation 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.
### 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:
```yaml
dependencies-cache-key: |
**/gradle.properties
gradle/dependency-locking/**
dependencies-cache-exact: true
configuration-cache-key: |
**/gradle.properties
gradle/dependency-locking/**
configuration-cache-exact: true
```
Coming up with a good cache key isn't trivial and depends on your build.
The above example isn't realistic.
Stick to the defaults unless you know what you are doing.
If you happen to use Gradle [dependency locking](https://docs.gradle.org/current/userguide/dependency_locking.html) you can make the dependencies cache more precise with the following configuration:
```yaml
dependencies-cache-enabled: true
dependencies-cache-key: gradle/dependency-locking/**
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`.
You can then use that link in subsequent actions of your workflow.
For example:
```yaml
# .github/workflows/gradle-build-pr.yml
name: Run Gradle on PRs
on: pull_request
jobs:
gradle:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: eskatos/gradle-command-action@v1
with:
arguments: build
id: gradle
- uses: example/action-that-comments-on-the-pr@v0
if: failure()
with:
comment: Build failed ${{ steps.gradle.outputs.build-scan-url }}
```
+33
View File
@@ -0,0 +1,33 @@
import * as cacheWrapper from '../src/cache-wrapper'
import * as path from 'path'
describe('cache', () => {
describe('can extract gradle wrapper slug', () => {
it('from wrapper properties file', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFrom(
path.resolve(
'__tests__/data/basic/gradle/wrapper/gradle-wrapper.properties'
)
)
expect(version).toBe('6.5-bin')
})
it('for -bin dist', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip'
)
expect(version).toBe('6.5-bin')
})
it('for -all dist', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-all.zip'
)
expect(version).toBe('6.5-all')
})
it('for milestone', async () => {
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6-milestone-1-all.zip'
)
expect(version).toBe('6.6-milestone-1-all')
})
})
})
+39
View File
@@ -0,0 +1,39 @@
import * as cryptoUtils from '../src/crypto-utils'
import * as path from 'path'
describe('crypto-utils', () => {
describe('can hash', () => {
it('a directory', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/gradle')
)
expect(hash).toBe(
process.platform === 'win32'
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
: '4ebb65b45e6f6796d5ec6ace96e9471cc6573d294c54f99c4920fe5328e75bab'
)
})
it('a directory with a glob', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/'),
['gradle/**']
)
expect(hash).toBe(
process.platform === 'win32'
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
: '4ebb65b45e6f6796d5ec6ace96e9471cc6573d294c54f99c4920fe5328e75bab'
)
})
it('a directory with globs', async () => {
const hash = await cryptoUtils.hashFiles(
path.resolve('__tests__/data/basic/'),
['**/*.gradle', 'gradle/**']
)
expect(hash).toBe(
process.platform === 'win32'
? 'd9b66fded38f79f601ce745d64ed726a8df8c0b242b02bcd2c1d331f54742ad6'
: 'aa72a837158799fbadd1c4aff94fcc2b5bb9dc6ad8d12f6337d047d4b0c8f79e'
)
})
})
})
+6
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
View File
@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
+11
View File
@@ -0,0 +1,11 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('junit:junit:4.12')
}
Binary file not shown.
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+185
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
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
+10
View File
@@ -0,0 +1,10 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html
*/
rootProject.name = 'basic'
@@ -0,0 +1,10 @@
package basic;
import org.junit.Test;
public class BasicTest {
@Test
public void test() {
assert true;
}
}
+51 -8
View File
@@ -1,13 +1,56 @@
name: Build with Gradle
description: A collection of actions for building Gradle projects, as well as generating a dependency graph via Dependency Submission.
name: "Gradle Command"
description: 'Execute Gradle Command Line'
author: 'Paul Merlin <paul@nospere.org>'
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
inputs:
wrapper-directory:
description: Path to the Gradle Wrapper directory
required: false
gradle-executable:
description: Path to the Gradle executable
required: false
gradle-version:
description: Gradle version to use
required: false
build-root-directory:
description: Path to the root directory of the build
required: false
arguments:
description: Gradle command line arguments, see gradle --help
required: false
wrapper-cache-enabled:
description: Whether caching wrapper installation is enabled or not, default to 'true'
required: false
dependencies-cache-enabled:
description: Whether caching dependencies is enabled or not, default to 'false'
required: 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
configuration-cache-enabled:
description: Whether caching build configuration is enabled or not, default to 'false'
required: 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
outputs:
build-scan-url:
description: Link to the build scan if any
runs:
using: "composite"
steps:
- run: |
echo "::error::The path 'gradle/actions' is not a valid action. Please use 'gradle/actions/setup-gradle' or 'gradle/actions/dependency-submission'."
exit 1
shell: bash
using: 'node12'
main: 'dist/main/index.js'
post: 'dist/post/index.js'
post-if: success()
branding:
icon: 'box'
-70
View File
@@ -1,70 +0,0 @@
name: Gradle Dependency Submission
description: Generates a dependency graph for a Gradle project and submits it via the Dependency Submission API
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.
If not provided, it is assumed that the project uses the Gradle Wrapper.
required: false
build-root-directory:
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
required: false
cache-encryption-key:
description: |
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A suitable key can be generated with `openssl rand -base64 16`.
Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false
dependency-graph-action:
description: |
Specifies how the dependency-graph should be handled by this action. By default a dependency-graph will be generated and submitted.
Valid values are:
'generate-and-submit' (default): Generates a dependency graph for the project and submits it in the same Job.
'generate-and-save': Generates a dependency graph for the project and saves it as a workflow artifact.
'retrieve-and-submit': Retrieves a previously saved dependency-graph and submits it to the repository.
The `generate-and-upload` and `download-and-submit` options are designed to be used in an untrusted workflow scenario,
where the workflow generating the dependency-graph cannot (or should not) be given the `contents: write` permissions
required to submit via the Dependency Submission API.
required: false
default: 'generate-and-submit'
runs:
using: "composite"
steps:
- name: Generate and submit dependency graph
if: ${{ inputs.dependency-graph-action == 'generate-and-submit' }}
uses: gradle/gradle-build-action@v3-beta
with:
dependency-graph: 'generate-and-submit'
dependency-graph-continue-on-failure: false
gradle-version: ${{ inputs.gradle-version }}
build-root-directory: ${{ inputs.build-root-directory }}
cache-encryption-key: ${{ inputs.cache-encryption-key }}
arguments: |
--no-configure-on-demand
--dependency-verification=off
--stacktrace
:ForceDependencyResolutionPlugin_resolveAllDependencies
- name: Generate and save dependency graph
if: ${{ inputs.dependency-graph-action == 'generate-and-save' }}
uses: gradle/gradle-build-action@v3-beta
with:
dependency-graph: generate-and-upload
dependency-graph-continue-on-failure: false
gradle-version: ${{ inputs.gradle-version }}
build-root-directory: ${{ inputs.build-root-directory }}
cache-encryption-key: ${{ inputs.cache-encryption-key }}
arguments: |
--no-configure-on-demand
--dependency-verification=off
--stacktrace
:ForceDependencyResolutionPlugin_resolveAllDependencies
- name: Download and submit dependency graph
if: ${{ inputs.dependency-graph-action == 'retrieve-and-submit' }}
uses: gradle/gradle-build-action@v3-beta
with:
dependency-graph: download-and-submit
dependency-graph-continue-on-failure: false
cache-disabled: true
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts', 'json'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true,
setupFilesAfterEnv: ['./jest.setup.js']
}
+1
View File
@@ -0,0 +1 @@
jest.setTimeout(10000) // in milliseconds
+7294
View File
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
{
"name": "gradle-command-action",
"version": "1.0.0",
"private": true,
"description": "Execute Gradle Command Line",
"scripts": {
"format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts",
"lint": "eslint src/**/*.ts",
"build": "ncc build src/main.ts --out dist/main --minify && ncc build src/post.ts --out dist/post --minify",
"test": "jest",
"all": "npm run format && npm run lint && npm run build && npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/eskatos/gradle-command-action.git"
},
"keywords": [
"github",
"actions",
"github-actions",
"gradle"
],
"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"
},
"devDependencies": {
"@types/jest": "26.0.0",
"@types/node": "12.12.6",
"@types/unzipper": "0.10.3",
"@typescript-eslint/parser": "3.3.0",
"@zeit/ncc": "0.22.3",
"eslint": "7.3.0",
"eslint-plugin-github": "4.0.1",
"eslint-plugin-jest": "23.16.0",
"jest": "26.0.1",
"jest-circus": "26.0.1",
"js-yaml": "3.14.0",
"prettier": "2.0.5",
"ts-jest": "26.1.1",
"typescript": "3.9.5"
}
}
-124
View File
@@ -1,124 +0,0 @@
name: Setup Gradle environment
description: Configures the local environment for Gradle execution, downloading and installing a specified Gradle version if required.
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
cache-disabled:
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
required: false
default: false
cache-read-only:
description: |
When 'true', existing entries will be read from the cache but no entries will be written.
By default this value is 'false' for workflows on the GitHub default branch and 'true' for workflows on other branches.
required: false
default: ${{ github.event.repository != null && github.ref_name != github.event.repository.default_branch }}
cache-write-only:
description: |
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
Setting this to 'true' implies cache-read-only will be 'false'.
required: false
default: false
cache-overwrite-existing:
description: When 'true', a pre-existing Gradle User Home will not prevent the cache from being restored.
required: false
default: false
cache-encryption-key:
description: |
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A suitable key can be generated with `openssl rand -base64 16`.
Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false
gradle-home-cache-includes:
description: Paths within Gradle User Home to cache.
required: false
default: |
caches
notifications
gradle-home-cache-excludes:
description: Paths within Gradle User Home to exclude from cache.
required: false
# e.g. Use the following setting to prevent the local build cache from being saved/restored
# gradle-home-cache-excludes: |
# caches/build-cache-1
gradle-home-cache-cleanup:
description: When 'true', the action will attempt to remove any stale/unused entries from the Gradle User Home prior to saving to the GitHub Actions cache.
required: false
default: false
add-job-summary:
description: Specifies when a Job Summary should be inluded in the action results. Valid values are 'never', 'always' (default), and 'on-failure'.
required: false
default: 'always'
add-job-summary-as-pr-comment:
description: Specifies when each Job Summary should be added as a PR comment. Valid values are 'never' (default), 'always', and 'on-failure'. No action will be taken if the workflow was not triggered from a pull request.
required: false
default: 'never'
dependency-graph:
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit', 'generate-and-upload' and 'download-and-submit'.
required: false
default: 'disabled'
dependency-graph-continue-on-failure:
description: When 'false' a failure to generate or submit a dependency graph will fail the Step or Job. When 'true' a warning will be emitted but no failure will result.
required: false
default: true
artifact-retention-days:
description: Specifies the number of days to retain any artifacts generated by the action. If not set, the default retention settings for the repository will apply.
required: false
# EXPERIMENTAL & INTERNAL ACTION INPUTS
# 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`.
# Use at your own risk!
workflow-job-context:
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
required: false
default: ${{ toJSON(matrix) }}
github-token:
description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
default: ${{ github.token }}
required: false
outputs:
build-scan-url:
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.
gradle-version:
description: Version of Gradle that was setup by the action
runs:
using: "composite"
steps:
- uses: gradle/gradle-build-action@v3-beta
with:
gradle-version: ${{ inputs.gradle-version }}
cache-disabled: ${{ inputs.cache-disabled }}
cache-read-only: ${{ inputs.cache-read-only }}
cache-write-only: ${{ inputs.cache-write-only }}
cache-overwrite-existing: ${{ inputs.cache-overwrite-existing }}
cache-encryption-key: ${{ inputs.cache-encryption-key }}
gradle-home-cache-includes: ${{ inputs.gradle-home-cache-includes }}
gradle-home-cache-excludes: ${{ inputs.gradle-home-cache-excludes }}
add-job-summary: ${{ inputs.add-job-summary }}
add-job-summary-as-pr-comment: ${{ inputs.add-job-summary-as-pr-comment }}
dependency-graph: ${{ inputs.dependency-graph }}
dependency-graph-continue-on-failure: ${{ inputs.dependency-graph-continue-on-failure }}
artifact-retention-days: ${{ inputs.artifact-retention-days }}
workflow-job-context: ${{ inputs.workflow-job-context }}
github-token: ${{ inputs.github-token }}
+97
View File
@@ -0,0 +1,97 @@
import path from 'path'
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'
const CONFIGURATION_CACHE_PATH = 'CONFIGURATION_CACHE_PATH'
const CONFIGURATION_CACHE_KEY = 'CONFIGURATION_CACHE_KEY'
const CONFIGURATION_CACHE_RESULT = 'CONFIGURATION_CACHE_RESULT'
export async function restoreCachedConfiguration(
rootDir: string
): Promise<void> {
if (isConfigurationCacheDisabled()) return
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 cacheKeyGlobs = inputCacheKeyGlobs('configuration-cache-key')
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
const cacheKeyPrefix = 'configuration-'
const cacheKey = `${cacheKeyPrefix}${hash}`
core.saveState(CONFIGURATION_CACHE_KEY, cacheKey)
const cacheResult = await cache.restoreCache(
[cachePath],
cacheKey,
inputCacheExact ? [] : [cacheKeyPrefix]
)
if (!cacheResult) {
core.info(
'Configuration cache not found, expect task graph calculation.'
)
return
}
core.saveState(CONFIGURATION_CACHE_RESULT, cacheResult)
core.info(`Configuration restored from cache key: ${cacheResult}`)
return
}
export async function cacheConfiguration(): Promise<void> {
if (isConfigurationCacheDisabled()) return
const cachePath = core.getState(CONFIGURATION_CACHE_PATH)
const cacheKey = core.getState(CONFIGURATION_CACHE_KEY)
const cacheResult = core.getState(CONFIGURATION_CACHE_RESULT)
if (!cachePath || !fs.existsSync(cachePath)) {
core.debug('No configuration to cache.')
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Configuration cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
const locksDeleted = tryDeleteFiles([
path.resolve(cachePath, 'configuration-cache.lock')
])
if (!locksDeleted) {
core.warning(
'Unable to delete configuration lock files, try using --no-daemon or stopping the daemon last if you have several Gradle steps, not saving cache.'
)
return
}
try {
await cache.saveCache([cachePath], 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
}
function isConfigurationCacheDisabled(): boolean {
return !github.inputBoolean('configuration-cache-enabled', false)
}
+120
View File
@@ -0,0 +1,120 @@
import * as path from 'path'
import * as fs from 'fs'
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'
const DEPENDENCIES_CACHE_KEY = 'DEPENDENCIES_CACHE_KEY'
const DEPENDENCIES_CACHE_RESULT = 'DEPENDENCIES_CACHE_RESULT'
export async function restoreCachedDependencies(
rootDir: string
): Promise<void> {
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 cacheKeyGlobs = inputCacheKeyGlobs('dependencies-cache-key')
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
const cacheKeyPrefix = 'dependencies-'
const cacheKey = `${cacheKeyPrefix}${hash}`
core.saveState(DEPENDENCIES_CACHE_KEY, cacheKey)
const cacheResult = await cache.restoreCache(
[cachePath],
cacheKey,
inputCacheExact ? [] : [cacheKeyPrefix]
)
if (!cacheResult) {
core.info('Dependencies cache not found, expect dependencies download.')
return
}
core.saveState(DEPENDENCIES_CACHE_RESULT, cacheResult)
core.info(`Dependencies restored from cache key: ${cacheResult}`)
return
}
export async function cacheDependencies(): Promise<void> {
if (isDependenciesCacheDisabled()) return
const cachePath = core.getState(DEPENDENCIES_CACHE_PATH)
const cacheKey = core.getState(DEPENDENCIES_CACHE_KEY)
const cacheResult = core.getState(DEPENDENCIES_CACHE_RESULT)
if (!cachePath || !fs.existsSync(cachePath)) {
core.debug('No dependencies to cache.')
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Dependencies cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
const locksDeleted = tryDeleteFiles([
path.resolve(cachePath, 'modules-2.lock')
])
if (!locksDeleted) {
core.warning(
'Unable to delete dependencies lock files, try using --no-daemon or stopping the daemon last if you have several Gradle steps, not saving cache.'
)
return
}
try {
await cache.saveCache([cachePath], 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
}
export function tryDeleteFiles(filePaths: string[]): boolean {
let failure = false
for (const filePath of filePaths) {
if (fs.existsSync(filePath)) {
try {
fs.unlinkSync(filePath)
} catch (error) {
failure = true
}
}
}
return !failure
}
function isDependenciesCacheDisabled(): boolean {
return !github.inputBoolean('dependencies-cache-enabled', false)
}
export function inputCacheKeyGlobs(input: string): string[] {
const inputValue = github.inputArrayOrNull(input)
return inputValue
? inputValue
: [
'**/*.gradle',
'**/*.gradle.kts',
'**/gradle.properties',
'gradle/**'
]
}
+110
View File
@@ -0,0 +1,110 @@
import * as path from 'path'
import * as fs from 'fs'
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'
export async function restoreCachedWrapperDist(
gradlewDirectory: string | null
): Promise<void> {
if (isWrapperCacheDisabled()) return
if (gradlewDirectory == null) return
const wrapperSlug = extractGradleWrapperSlugFrom(
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}`
)
if (fs.existsSync(wrapperCachePath)) return
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.'
)
return
}
core.saveState(WRAPPER_CACHE_RESULT, restoredKey)
core.info(`Wrapper installation restored from cache key: ${restoredKey}`)
return
}
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)
if (!cachePath || !fs.existsSync(cachePath)) {
core.debug('No wrapper installation to cache.')
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Wrapper installation cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
try {
await cache.saveCache([cachePath], 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
}
export function extractGradleWrapperSlugFrom(
wrapperProperties: string
): string | null {
const props = fs.readFileSync(wrapperProperties, {encoding: 'utf8'})
const distUrlLine = props
.split('\n')
.find(line => line.startsWith('distributionUrl'))
if (!distUrlLine) return null
return extractGradleWrapperSlugFromDistUri(distUrlLine.substr(16).trim())
}
export function extractGradleWrapperSlugFromDistUri(
distUri: string
): string | null {
const regex = /.*gradle-(.*-(bin|all))\.zip/
const match = distUri.match(regex)
return match ? match[1] : null
}
function isWrapperCacheDisabled(): boolean {
return !github.inputBoolean('wrapper-cache-enabled', true)
}
+44
View File
@@ -0,0 +1,44 @@
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[] = ['**'],
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')
}
+45
View File
@@ -0,0 +1,45 @@
import * as exec from '@actions/exec'
import * as cacheDependencies from './cache-dependencies'
import * as cacheConfiguration from './cache-configuration'
export async function execute(
executable: string,
root: string,
argv: string[]
): Promise<BuildResult> {
await cacheDependencies.restoreCachedDependencies(root)
await cacheConfiguration.restoreCachedConfiguration(root)
let publishing = false
let buildScanUrl: string | undefined
const status: number = await exec.exec(executable, argv, {
cwd: root,
ignoreReturnCode: true,
listeners: {
stdline: (line: string) => {
if (line.startsWith('Publishing build scan...')) {
publishing = true
}
if (publishing && line.length === 0) {
publishing = false
}
if (publishing && line.startsWith('http')) {
buildScanUrl = line.trim()
publishing = false
}
}
}
})
return new BuildResultImpl(status, buildScanUrl)
}
export interface BuildResult {
readonly status: number
readonly buildScanUrl?: string
}
class BuildResultImpl implements BuildResult {
constructor(readonly status: number, readonly buildScanUrl?: string) {}
}
+24
View File
@@ -0,0 +1,24 @@
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'
}
+9
View File
@@ -0,0 +1,9 @@
const IS_WINDOWS = process.platform === 'win32'
export function wrapperFilename(): string {
return IS_WINDOWS ? 'gradlew.bat' : 'gradlew'
}
export function installScriptFilename(): string {
return IS_WINDOWS ? 'gradle.bat' : 'gradle'
}
+75
View File
@@ -0,0 +1,75 @@
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'
import * as provision from './provision'
// Invoked by GitHub Actions
export async function run(): Promise<void> {
try {
const baseDirectory = process.env[`GITHUB_WORKSPACE`] || ''
const result = await execution.execute(
await resolveGradleExecutable(baseDirectory),
resolveBuildRootDirectory(baseDirectory),
parseCommandLineArguments()
)
if (result.buildScanUrl) {
core.setOutput('build-scan-url', result.buildScanUrl)
}
if (result.status !== 0) {
core.setFailed(`Gradle process exited with status ${result.status}`)
}
} catch (error) {
core.setFailed(error.message)
}
}
run()
async function resolveGradleExecutable(baseDirectory: string): Promise<string> {
const gradleVersion = github.inputOrNull('gradle-version')
if (gradleVersion !== null && gradleVersion !== 'wrapper') {
return path.resolve(await provision.gradleVersion(gradleVersion))
}
const gradleExecutable = github.inputOrNull('gradle-executable')
if (gradleExecutable !== null) {
if (gradleExecutable.endsWith(gradlew.wrapperFilename())) {
await cacheWrapper.restoreCachedWrapperDist(
path.resolve(gradleExecutable, '..')
)
}
return path.resolve(baseDirectory, gradleExecutable)
}
const wrapperDirectory = github.inputOrNull('wrapper-directory')
const gradlewDirectory =
wrapperDirectory !== null
? path.join(baseDirectory, wrapperDirectory)
: baseDirectory
await cacheWrapper.restoreCachedWrapperDist(gradlewDirectory)
return path.resolve(gradlewDirectory, gradlew.wrapperFilename())
}
function resolveBuildRootDirectory(baseDirectory: string): string {
const buildRootDirectory = github.inputOrNull('build-root-directory')
const resolvedBuildRootDirectory =
buildRootDirectory === null
? path.resolve(baseDirectory)
: path.resolve(baseDirectory, buildRootDirectory)
return resolvedBuildRootDirectory
}
function parseCommandLineArguments(): string[] {
const input = github.inputOrNull('arguments')
return input === null ? [] : parseArgsStringToArgv(input)
}
+12
View File
@@ -0,0 +1,12 @@
import * as cacheWrapper from './cache-wrapper'
import * as cacheDependencies from './cache-dependencies'
import * as cacheConfiguration from './cache-configuration'
// Invoked by GitHub Actions
export async function run(): Promise<void> {
await cacheWrapper.cacheWrapperDist()
await cacheDependencies.cacheDependencies()
await cacheConfiguration.cacheConfiguration()
}
run()
+175
View File
@@ -0,0 +1,175 @@
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 core from '@actions/core'
import * as io from '@actions/io'
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'
/**
* @return Gradle executable path
*/
export async function gradleVersion(version: string): Promise<string> {
switch (version) {
case 'current':
return gradleCurrent()
case 'rc':
return gradleReleaseCandidate()
case 'nightly':
return gradleNightly()
case 'release-nightly':
return gradleReleaseNightly()
default:
return gradle(version)
}
}
async function gradleCurrent(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/current`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
}
async function gradleReleaseCandidate(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/release-candidate`
)
if (versionInfo) {
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
}
return gradleCurrent()
}
async function gradleNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/nightly`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
}
async function gradleReleaseNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/release-nightly`
)
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
}
async function gradle(version: string): Promise<string> {
const versionInfo = await findGradleVersionDeclaration(version)
if (!versionInfo) {
throw new Error(`Gradle version ${version} does not exists`)
}
return provisionGradle(versionInfo.version, versionInfo.downloadUrl)
}
async function gradleVersionDeclaration(
url: string
): Promise<GradleVersionInfo> {
return await httpGetGradleVersion(url)
}
async function findGradleVersionDeclaration(
version: string
): Promise<GradleVersionInfo | undefined> {
const gradleVersions = await httpGetGradleVersions(
`${gradleVersionsBaseUrl}/all`
)
return gradleVersions.find((entry: GradleVersionInfo) => {
return entry.version === version
})
}
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
}
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 executable = executableFrom(installDir)
fs.chmodSync(executable, '755')
core.info(`Provisioned Gradle executable ${executable}`)
toolCache.cacheDir(installDir, 'gradle', version)
return executable
}
function executableFrom(installDir: string): string {
return path.join(installDir, 'bin', `${gradlew.installScriptFilename()}`)
}
async function httpGetGradleVersion(url: string): Promise<GradleVersionInfo> {
return JSON.parse(await httpGetString(url))
}
async function httpGetGradleVersions(
url: string
): Promise<GradleVersionInfo[]> {
return JSON.parse(await httpGetString(url))
}
async function httpGetString(url: string): Promise<string> {
const response = await httpc.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)
})
})
}
interface GradleVersionInfo {
version: string
downloadUrl: string
}
+63
View File
@@ -0,0 +1,63 @@
{
"compilerOptions": {
/* Basic Options */
"incremental": false, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
"removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"exclude": ["node_modules", "**/*.test.ts"]
}