diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml new file mode 100644 index 0000000..16c2117 --- /dev/null +++ b/.github/workflows/check-dist.yml @@ -0,0 +1,52 @@ +# `dist/index.js` is a special file in Actions. +# When you reference an action with `uses:` in a workflow, +# `index.js` is the code that will run. +# For our project, we generate this file through a build process +# from other source files. +# We need to make sure the checked-in `index.js` actually matches what we expect it to be. +name: Check dist/ + +on: + push: + branches: + - main + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: + +jobs: + check-dist: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: 12.x + + - name: Install dependencies + run: npm ci + + - name: Rebuild the dist/ directory + run: npm run build + + - name: Compare the expected and actual dist/ directories + run: | + if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then + echo "Detected uncommitted changes after build. See status below:" + git diff + exit 1 + fi + id: diff + + # If index.js was different than expected, upload the expected version as an artifact + - uses: actions/upload-artifact@v2 + if: ${{ failure() && steps.diff.conclusion == 'failure' }} + with: + name: dist + path: dist/ diff --git a/.github/workflows/licensed.yml b/.github/workflows/licensed.yml index ae62613..4c1dfe5 100644 --- a/.github/workflows/licensed.yml +++ b/.github/workflows/licensed.yml @@ -1,8 +1,12 @@ name: Licensed on: - push: {branches: main} - pull_request: {branches: main} + push: + branches: + - main + pull_request: + branches: + - main jobs: test: @@ -17,4 +21,4 @@ jobs: curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/2.12.2/licensed-2.12.2-linux-x64.tar.gz sudo tar -xzf licensed.tar.gz sudo mv licensed /usr/local/bin/licensed - - run: licensed status \ No newline at end of file + - run: licensed status diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 460d7dd..a5dd3b7 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -47,17 +47,6 @@ jobs: run: npm run lint - name: Build & Test run: npm run test - - name: Ensure dist/ folder is up-to-date - if: ${{ runner.os == 'Linux' }} - shell: bash - run: | - npm run build - if [ "$(git diff --ignore-space-at-eol | wc -l)" -gt "0" ]; then - echo "Detected uncommitted changes after build. See status below:" - git diff - exit 1 - fi - # End to end save and restore test-save: diff --git a/__tests__/restore.test.ts b/__tests__/restore.test.ts index 446237c..4761782 100644 --- a/__tests__/restore.test.ts +++ b/__tests__/restore.test.ts @@ -68,7 +68,7 @@ test("restore on GHES should no-op", async () => { expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledWith(false); expect(logWarningMock).toHaveBeenCalledWith( - "Cache action is not supported on GHES" + "Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details" ); }); diff --git a/__tests__/save.test.ts b/__tests__/save.test.ts index b806d50..30178a2 100644 --- a/__tests__/save.test.ts +++ b/__tests__/save.test.ts @@ -111,7 +111,7 @@ test("save on GHES should no-op", async () => { expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(logWarningMock).toHaveBeenCalledWith( - "Cache action is not supported on GHES" + "Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details" ); }); diff --git a/dist/restore/index.js b/dist/restore/index.js index e13e548..59dd8fb 100644 --- a/dist/restore/index.js +++ b/dist/restore/index.js @@ -49218,7 +49218,7 @@ function run() { return __awaiter(this, void 0, void 0, function* () { try { if (utils.isGhes()) { - utils.logWarning("Cache action is not supported on GHES"); + utils.logWarning("Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details"); utils.setCacheHitOutput(false); return; } diff --git a/dist/save/index.js b/dist/save/index.js index 1aad367..bd78ec6 100644 --- a/dist/save/index.js +++ b/dist/save/index.js @@ -47154,11 +47154,15 @@ const cache = __importStar(__webpack_require__(692)); const core = __importStar(__webpack_require__(470)); const constants_1 = __webpack_require__(196); const utils = __importStar(__webpack_require__(443)); +// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in +// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to +// throw an uncaught exception. Instead of failing this action, just warn. +process.on("uncaughtException", e => utils.logWarning(e.message)); function run() { return __awaiter(this, void 0, void 0, function* () { try { if (utils.isGhes()) { - utils.logWarning("Cache action is not supported on GHES"); + utils.logWarning("Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details"); return; } if (!utils.isValidEvent()) { diff --git a/examples.md b/examples.md index f3d6788..1f6ecef 100644 --- a/examples.md +++ b/examples.md @@ -1,39 +1,44 @@ # Examples -- [Examples](#examples) - - [C# - NuGet](#c---nuget) - - [D - DUB](#d---dub) - - [Elixir - Mix](#elixir---mix) - - [Go - Modules](#go---modules) - - [Haskell - Cabal](#haskell---cabal) - - [Java - Gradle](#java---gradle) - - [Java - Maven](#java---maven) - - [Node - npm](#node---npm) - - [macOS and Ubuntu](#macos-and-ubuntu) - - [Windows](#windows) - - [Using multiple systems and `npm config`](#using-multiple-systems-and-npm-config) - - [Node - Lerna](#node---lerna) - - [Node - Yarn](#node---yarn) - - [Node - Yarn 2](#node---yarn-2) - - [OCaml/Reason - esy](#ocamlreason---esy) - - [PHP - Composer](#php---composer) - - [Python - pip](#python---pip) - - [Simple example](#simple-example) - - [Multiple OSes in a workflow](#multiple-oss-in-a-workflow) - - [Using pip to get cache location](#using-pip-to-get-cache-location) - - [Using a script to get cache location](#using-a-script-to-get-cache-location) - - [Python - pipenv](#python---pipenv) - - [R - renv](#r---renv) - - [Simple example](#simple-example-1) - - [Multiple OSes in a workflow](#multiple-oss-in-a-workflow-1) - - [Ruby - Bundler](#ruby---bundler) - - [Rust - Cargo](#rust---cargo) - - [Scala - SBT](#scala---sbt) - - [Swift, Objective-C - Carthage](#swift-objective-c---carthage) - - [Swift, Objective-C - CocoaPods](#swift-objective-c---cocoapods) - - [Swift - Swift Package Manager](#swift---swift-package-manager) +- [C# - NuGet](#c---nuget) +- [D - DUB](#d---dub) + - [POSIX](#posix) + - [Windows](#windows) +- [Elixir - Mix](#elixir---mix) +- [Go - Modules](#go---modules) + - [Linux](#linux) + - [macOS](#macos) + - [Windows](#windows-1) +- [Haskell - Cabal](#haskell---cabal) +- [Java - Gradle](#java---gradle) +- [Java - Maven](#java---maven) +- [Node - npm](#node---npm) + - [macOS and Ubuntu](#macos-and-ubuntu) + - [Windows](#windows-2) + - [Using multiple systems and `npm config`](#using-multiple-systems-and-npm-config) +- [Node - Lerna](#node---lerna) +- [Node - Yarn](#node---yarn) +- [Node - Yarn 2](#node---yarn-2) +- [OCaml/Reason - esy](#ocamlreason---esy) +- [PHP - Composer](#php---composer) +- [Python - pip](#python---pip) + - [Simple example](#simple-example) + - [Multiple OS's in a workflow](#multiple-oss-in-a-workflow) + - [Multiple OS's in a workflow with a matrix](#multiple-oss-in-a-workflow-with-a-matrix) + - [Using pip to get cache location](#using-pip-to-get-cache-location) +- [Python - pipenv](#python---pipenv) +- [R - renv](#r---renv) + - [Simple example](#simple-example-1) + - [Multiple OS's in a workflow](#multiple-oss-in-a-workflow-1) +- [Ruby - Bundler](#ruby---bundler) +- [Rust - Cargo](#rust---cargo) +- [Scala - SBT](#scala---sbt) +- [Swift, Objective-C - Carthage](#swift-objective-c---carthage) +- [Swift, Objective-C - CocoaPods](#swift-objective-c---cocoapods) +- [Swift - Swift Package Manager](#swift---swift-package-manager) ## C# - NuGet + Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/package-references-in-project-files#locking-dependencies): ```yaml @@ -47,10 +52,11 @@ Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/packa Depending on the environment, huge packages might be pre-installed in the global cache folder. With `actions/cache@v2` you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/main/packages/glob#exclude-patterns) + ```yaml - uses: actions/cache@v2 with: - path: | + path: | ~/.nuget/packages !~/.nuget/packages/unwanted key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} @@ -111,10 +117,40 @@ steps: ## Go - Modules +### Linux + ```yaml - uses: actions/cache@v2 with: - path: ~/go/pkg/mod + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- +``` + +### macOS + +```yaml +- uses: actions/cache@v2 + with: + path: | + ~/Library/Caches/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- +``` + +### Windows + +```yaml +- uses: actions/cache@v2 + with: + path: | + %LocalAppData%\go-build + ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- @@ -137,6 +173,8 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba ## Java - Gradle +>Note: Ensure no Gradle daemons are running anymore when your workflow completes. Creating the cache package might fail due to locks being held by Gradle. Refer to the [Gradle Daemon documentation](https://docs.gradle.org/current/userguide/gradle_daemon.html) on how to disable or stop the Gradle Daemons. + ```yaml - uses: actions/cache@v2 with: @@ -239,8 +277,8 @@ The yarn cache directory will depend on your operating system and version of `ya ${{ runner.os }}-yarn- ``` - ## Node - Yarn 2 + The yarn 2 cache directory will depend on your config. See https://yarnpkg.com/configuration/yarnrc#cacheFolder for more info. ```yaml @@ -258,6 +296,7 @@ The yarn 2 cache directory will depend on your config. See https://yarnpkg.com/c ``` ## OCaml/Reason - esy + Esy allows you to export built dependencies and import pre-built dependencies. ```yaml - name: Restore Cache @@ -278,13 +317,12 @@ Esy allows you to export built dependencies and import pre-built dependencies. ...(Build job)... # Re-export dependencies if anything has changed or if it is the first time - - name: Setting dependency cache + - name: Setting dependency cache run: | esy export-dependencies if: steps.restore-cache.outputs.cache-hit != 'true' ``` - ## PHP - Composer ```yaml @@ -305,11 +343,13 @@ Esy allows you to export built dependencies and import pre-built dependencies. For pip, the cache directory will vary by OS. See https://pip.pypa.io/en/stable/reference/pip_install/#caching Locations: - - Ubuntu: `~/.cache/pip` - - Windows: `~\AppData\Local\pip\Cache` - - macOS: `~/Library/Caches/pip` + +- Ubuntu: `~/.cache/pip` +- Windows: `~\AppData\Local\pip\Cache` +- macOS: `~/Library/Caches/pip` ### Simple example + ```yaml - uses: actions/cache@v2 with: @@ -395,12 +435,17 @@ jobs: ## Python - pipenv ```yaml +- name: Set up Python + # The actions/cache step below uses this id to get the exact python version + id: setup-python + uses: actions/setup-python@v2 + + ⋮ + - uses: actions/cache@v2 with: path: ~/.local/share/virtualenvs - key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }} - restore-keys: | - ${{ runner.os }}-pipenv- + key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }} ``` ## R - renv @@ -408,11 +453,13 @@ jobs: For renv, the cache directory will vary by OS. Look at https://rstudio.github.io/renv/articles/renv.html#cache Locations: - - Ubuntu: `~/.local/share/renv` - - macOS: `~/Library/Application Support/renv` - - Windows: `%LOCALAPPDATA%/renv` + +- Ubuntu: `~/.local/share/renv` +- macOS: `~/Library/Application Support/renv` +- Windows: `%LOCALAPPDATA%/renv` ### Simple example + ```yaml - uses: actions/cache@v2 with: @@ -474,9 +521,11 @@ whenever possible: - uses: actions/cache@v2 with: path: | - ~/.cargo/registry - ~/.cargo/git - target + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} ``` @@ -486,7 +535,7 @@ whenever possible: - name: Cache SBT uses: actions/cache@v2 with: - path: | + path: | ~/.ivy2/cache ~/.sbt key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }} diff --git a/package-lock.json b/package-lock.json index b6dbcc0..2314b78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cache", - "version": "2.1.5", + "version": "2.1.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6473,9 +6473,9 @@ } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", "dev": true, "requires": { "async-limiter": "~1.0.0" diff --git a/package.json b/package.json index 167fe9f..5fe21e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cache", - "version": "2.1.5", + "version": "2.1.6", "private": true, "description": "Cache dependencies and build outputs", "main": "dist/restore/index.js", diff --git a/src/restore.ts b/src/restore.ts index 0fa6333..d411459 100644 --- a/src/restore.ts +++ b/src/restore.ts @@ -7,7 +7,9 @@ import * as utils from "./utils/actionUtils"; async function run(): Promise { try { if (utils.isGhes()) { - utils.logWarning("Cache action is not supported on GHES"); + utils.logWarning( + "Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details" + ); utils.setCacheHitOutput(false); return; } diff --git a/src/save.ts b/src/save.ts index 5e52249..fc0eb73 100644 --- a/src/save.ts +++ b/src/save.ts @@ -4,10 +4,17 @@ import * as core from "@actions/core"; import { Events, Inputs, State } from "./constants"; import * as utils from "./utils/actionUtils"; +// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in +// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to +// throw an uncaught exception. Instead of failing this action, just warn. +process.on("uncaughtException", e => utils.logWarning(e.message)); + async function run(): Promise { try { if (utils.isGhes()) { - utils.logWarning("Cache action is not supported on GHES"); + utils.logWarning( + "Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details" + ); return; }