From 5fb96a5419bdfbb71940a0264e709f79b49814aa Mon Sep 17 00:00:00 2001
From: eric sciple <ericsciple@users.noreply.github.com>
Date: Fri, 6 Mar 2020 17:52:32 -0500
Subject: [PATCH] Update tool-cache for download retries

---
 .github/workflows/workflow.yml |  14 ++
 __tests__/authutil.test.ts     |  37 +++--
 __tests__/installer.test.ts    |  64 ++++----
 __tests__/verify-node.sh       |  16 +-
 dist/index.js                  | 269 ++++++++++++++++++++++-----------
 package-lock.json              |  18 +--
 package.json                   |   2 +-
 src/installer.ts               |  23 +--
 8 files changed, 266 insertions(+), 177 deletions(-)

diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 945b0541..f55fd0cb 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -40,6 +40,20 @@ jobs:
       - name: Verify node and npm
         run: __tests__/verify-node.sh 10
 
+  test-fallback:
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Clear tool cache
+        run: mv "${{ runner.tool_cache }}" "${{ runner.tool_cache }}.old"
+      - name: Setup node 0.12.18
+        uses: ./
+        with:
+          node-version: 0.12.18
+      - name: Verify node
+        shell: bash
+        run: __tests__/verify-node.sh 0.12.18 SKIP_NPM
+
   test-proxy:
     runs-on: ubuntu-latest
     container:
diff --git a/__tests__/authutil.test.ts b/__tests__/authutil.test.ts
index c75d5b65..9f46b510 100644
--- a/__tests__/authutil.test.ts
+++ b/__tests__/authutil.test.ts
@@ -1,28 +1,27 @@
-import io = require('@actions/io');
-import fs = require('fs');
-import path = require('path');
-
-const tempDir = path.join(
-  __dirname,
-  'runner',
-  path.join(
-    Math.random()
-      .toString(36)
-      .substring(7)
-  ),
-  'temp'
-);
-
-const rcFile = path.join(tempDir, '.npmrc');
-
-process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
-process.env['RUNNER_TEMP'] = tempDir;
+import * as io from '@actions/io';
+import * as fs from 'fs';
+import * as path from 'path';
 import * as auth from '../src/authutil';
 
+let rcFile: string;
+
 describe('installer tests', () => {
   beforeAll(async () => {
+    const tempDir = path.join(
+      __dirname,
+      'runner',
+      path.join(
+        Math.random()
+          .toString(36)
+          .substring(7)
+      ),
+      'temp'
+    );
     await io.rmRF(tempDir);
     await io.mkdirP(tempDir);
+    process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
+    process.env['RUNNER_TEMP'] = tempDir;
+    rcFile = path.join(tempDir, '.npmrc');
   }, 100000);
 
   beforeEach(() => {
diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts
index e0ada325..7f76aebc 100644
--- a/__tests__/installer.test.ts
+++ b/__tests__/installer.test.ts
@@ -1,39 +1,39 @@
-import io = require('@actions/io');
-import fs = require('fs');
-import os = require('os');
-import path = require('path');
-
-const toolDir = path.join(
-  __dirname,
-  'runner',
-  path.join(
-    Math.random()
-      .toString(36)
-      .substring(7)
-  ),
-  'tools'
-);
-const tempDir = path.join(
-  __dirname,
-  'runner',
-  path.join(
-    Math.random()
-      .toString(36)
-      .substring(7)
-  ),
-  'temp'
-);
-
-process.env['RUNNER_TOOL_CACHE'] = toolDir;
-process.env['RUNNER_TEMP'] = tempDir;
+import * as io from '@actions/io';
+import * as tc from '@actions/tool-cache';
+import * as fs from 'fs';
+import * as os from 'os';
+import * as path from 'path';
 import * as installer from '../src/installer';
 
-const IS_WINDOWS = process.platform === 'win32';
+const isWindows = process.platform === 'win32';
+let toolDir: string;
 
 describe('installer tests', () => {
   beforeAll(async () => {
+    toolDir = path.join(
+      __dirname,
+      'runner',
+      path.join(
+        Math.random()
+          .toString(36)
+          .substring(7)
+      ),
+      'tools'
+    );
+    const tempDir = path.join(
+      __dirname,
+      'runner',
+      path.join(
+        Math.random()
+          .toString(36)
+          .substring(7)
+      ),
+      'temp'
+    );
     await io.rmRF(toolDir);
     await io.rmRF(tempDir);
+    process.env['RUNNER_TOOL_CACHE'] = toolDir;
+    process.env['RUNNER_TEMP'] = tempDir;
   }, 100000);
 
   it('Acquires version of node if no matching version is installed', async () => {
@@ -41,14 +41,14 @@ describe('installer tests', () => {
     const nodeDir = path.join(toolDir, 'node', '10.16.0', os.arch());
 
     expect(fs.existsSync(`${nodeDir}.complete`)).toBe(true);
-    if (IS_WINDOWS) {
+    if (isWindows) {
       expect(fs.existsSync(path.join(nodeDir, 'node.exe'))).toBe(true);
     } else {
       expect(fs.existsSync(path.join(nodeDir, 'bin', 'node'))).toBe(true);
     }
   }, 100000);
 
-  if (IS_WINDOWS) {
+  if (isWindows) {
     it('Falls back to backup location if first one doesnt contain correct version', async () => {
       await installer.getNode('5.10.1');
       const nodeDir = path.join(toolDir, 'node', '5.10.1', os.arch());
@@ -81,7 +81,7 @@ describe('installer tests', () => {
     const nodeDir = path.join(toolDir, 'node', '8.8.1', os.arch());
 
     expect(fs.existsSync(`${nodeDir}.complete`)).toBe(true);
-    if (IS_WINDOWS) {
+    if (isWindows) {
       expect(fs.existsSync(path.join(nodeDir, 'node.exe'))).toBe(true);
     } else {
       expect(fs.existsSync(path.join(nodeDir, 'bin', 'node'))).toBe(true);
diff --git a/__tests__/verify-node.sh b/__tests__/verify-node.sh
index 738eb460..797aa789 100755
--- a/__tests__/verify-node.sh
+++ b/__tests__/verify-node.sh
@@ -7,13 +7,17 @@ fi
 
 node_version="$(node --version)"
 echo "Found node version '$node_version'"
-if [ -z "$(echo $node_version | grep v$1)" ]; then
+if [ -z "$(echo $node_version | grep --fixed-strings v$1)" ]; then
   echo "Unexpected version"
   exit 1
 fi
 
-echo "Testing npm install"
-mkdir -p test-npm-install
-cd test-npm-install
-npm init -y || exit 1
-npm install @actions/core || exit 1
\ No newline at end of file
+if [ -z "$2" ]; then
+  echo "Testing npm install"
+  mkdir -p test-npm-install
+  cd test-npm-install
+  npm init -y || exit 1
+  npm install @actions/core || exit 1
+else
+  echo "Skip testing npm"
+fi
diff --git a/dist/index.js b/dist/index.js
index 65782bda..214ec571 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -10096,9 +10096,12 @@ const os = __importStar(__webpack_require__(87));
 const path = __importStar(__webpack_require__(622));
 const httpm = __importStar(__webpack_require__(539));
 const semver = __importStar(__webpack_require__(280));
+const stream = __importStar(__webpack_require__(794));
+const util = __importStar(__webpack_require__(669));
 const v4_1 = __importDefault(__webpack_require__(826));
 const exec_1 = __webpack_require__(986);
 const assert_1 = __webpack_require__(357);
+const retry_helper_1 = __webpack_require__(979);
 class HTTPError extends Error {
     constructor(httpStatusCode) {
         super(`Unexpected HTTP response: ${httpStatusCode}`);
@@ -10109,31 +10112,6 @@ class HTTPError extends Error {
 exports.HTTPError = HTTPError;
 const IS_WINDOWS = process.platform === 'win32';
 const userAgent = 'actions/tool-cache';
-// On load grab temp directory and cache directory and remove them from env (currently don't want to expose this)
-let tempDirectory = process.env['RUNNER_TEMP'] || '';
-let cacheRoot = process.env['RUNNER_TOOL_CACHE'] || '';
-// If directories not found, place them in common temp locations
-if (!tempDirectory || !cacheRoot) {
-    let baseLocation;
-    if (IS_WINDOWS) {
-        // On windows use the USERPROFILE env variable
-        baseLocation = process.env['USERPROFILE'] || 'C:\\';
-    }
-    else {
-        if (process.platform === 'darwin') {
-            baseLocation = '/Users';
-        }
-        else {
-            baseLocation = '/home';
-        }
-    }
-    if (!tempDirectory) {
-        tempDirectory = path.join(baseLocation, 'actions', 'temp');
-    }
-    if (!cacheRoot) {
-        cacheRoot = path.join(baseLocation, 'actions', 'cache');
-    }
-}
 /**
  * Download a tool from an url and stream it into a file
  *
@@ -10143,52 +10121,71 @@ if (!tempDirectory || !cacheRoot) {
  */
 function downloadTool(url, dest) {
     return __awaiter(this, void 0, void 0, function* () {
-        // Wrap in a promise so that we can resolve from within stream callbacks
-        return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
-            try {
-                const http = new httpm.HttpClient(userAgent, [], {
-                    allowRetries: true,
-                    maxRetries: 3
-                });
-                dest = dest || path.join(tempDirectory, v4_1.default());
-                yield io.mkdirP(path.dirname(dest));
-                core.debug(`Downloading ${url}`);
-                core.debug(`Downloading ${dest}`);
-                if (fs.existsSync(dest)) {
-                    throw new Error(`Destination file path ${dest} already exists`);
+        dest = dest || path.join(_getTempDirectory(), v4_1.default());
+        yield io.mkdirP(path.dirname(dest));
+        core.debug(`Downloading ${url}`);
+        core.debug(`Destination ${dest}`);
+        const maxAttempts = 3;
+        const minSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MIN_SECONDS', 10);
+        const maxSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS', 20);
+        const retryHelper = new retry_helper_1.RetryHelper(maxAttempts, minSeconds, maxSeconds);
+        return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
+            return yield downloadToolAttempt(url, dest || '');
+        }), (err) => {
+            if (err instanceof HTTPError && err.httpStatusCode) {
+                // Don't retry anything less than 500, except 408 Request Timeout and 429 Too Many Requests
+                if (err.httpStatusCode < 500 &&
+                    err.httpStatusCode !== 408 &&
+                    err.httpStatusCode !== 429) {
+                    return false;
                 }
-                const response = yield http.get(url);
-                if (response.message.statusCode !== 200) {
-                    const err = new HTTPError(response.message.statusCode);
-                    core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
-                    throw err;
-                }
-                const file = fs.createWriteStream(dest);
-                file.on('open', () => __awaiter(this, void 0, void 0, function* () {
-                    try {
-                        const stream = response.message.pipe(file);
-                        stream.on('close', () => {
-                            core.debug('download complete');
-                            resolve(dest);
-                        });
-                    }
-                    catch (err) {
-                        core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
-                        reject(err);
-                    }
-                }));
-                file.on('error', err => {
-                    file.end();
-                    reject(err);
-                });
             }
-            catch (err) {
-                reject(err);
-            }
-        }));
+            // Otherwise retry
+            return true;
+        });
     });
 }
 exports.downloadTool = downloadTool;
+function downloadToolAttempt(url, dest) {
+    return __awaiter(this, void 0, void 0, function* () {
+        if (fs.existsSync(dest)) {
+            throw new Error(`Destination file path ${dest} already exists`);
+        }
+        // Get the response headers
+        const http = new httpm.HttpClient(userAgent, [], {
+            allowRetries: false
+        });
+        const response = yield http.get(url);
+        if (response.message.statusCode !== 200) {
+            const err = new HTTPError(response.message.statusCode);
+            core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
+            throw err;
+        }
+        // Download the response body
+        const pipeline = util.promisify(stream.pipeline);
+        const responseMessageFactory = _getGlobal('TEST_DOWNLOAD_TOOL_RESPONSE_MESSAGE_FACTORY', () => response.message);
+        const readStream = responseMessageFactory();
+        let succeeded = false;
+        try {
+            yield pipeline(readStream, fs.createWriteStream(dest));
+            core.debug('download complete');
+            succeeded = true;
+            return dest;
+        }
+        finally {
+            // Error, delete dest before retry
+            if (!succeeded) {
+                core.debug('download failed');
+                try {
+                    yield io.rmRF(dest);
+                }
+                catch (err) {
+                    core.debug(`Failed to delete '${dest}'. ${err.message}`);
+                }
+            }
+        }
+    });
+}
 /**
  * Extract a .7z file
  *
@@ -10278,14 +10275,17 @@ function extractTar(file, dest, flags = 'xz') {
         // Create dest
         dest = yield _createExtractFolder(dest);
         // Determine whether GNU tar
+        core.debug('Checking tar --version');
         let versionOutput = '';
         yield exec_1.exec('tar --version', [], {
             ignoreReturnCode: true,
+            silent: true,
             listeners: {
                 stdout: (data) => (versionOutput += data.toString()),
                 stderr: (data) => (versionOutput += data.toString())
             }
         });
+        core.debug(versionOutput.trim());
         const isGnuTar = versionOutput.toUpperCase().includes('GNU TAR');
         // Initialize args
         const args = [flags];
@@ -10446,7 +10446,7 @@ function find(toolName, versionSpec, arch) {
     let toolPath = '';
     if (versionSpec) {
         versionSpec = semver.clean(versionSpec) || '';
-        const cachePath = path.join(cacheRoot, toolName, versionSpec, arch);
+        const cachePath = path.join(_getCacheDirectory(), toolName, versionSpec, arch);
         core.debug(`checking cache: ${cachePath}`);
         if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) {
             core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`);
@@ -10468,7 +10468,7 @@ exports.find = find;
 function findAllVersions(toolName, arch) {
     const versions = [];
     arch = arch || os.arch();
-    const toolPath = path.join(cacheRoot, toolName);
+    const toolPath = path.join(_getCacheDirectory(), toolName);
     if (fs.existsSync(toolPath)) {
         const children = fs.readdirSync(toolPath);
         for (const child of children) {
@@ -10487,7 +10487,7 @@ function _createExtractFolder(dest) {
     return __awaiter(this, void 0, void 0, function* () {
         if (!dest) {
             // create a temp dir
-            dest = path.join(tempDirectory, v4_1.default());
+            dest = path.join(_getTempDirectory(), v4_1.default());
         }
         yield io.mkdirP(dest);
         return dest;
@@ -10495,7 +10495,7 @@ function _createExtractFolder(dest) {
 }
 function _createToolPath(tool, version, arch) {
     return __awaiter(this, void 0, void 0, function* () {
-        const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
+        const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || '');
         core.debug(`destination ${folderPath}`);
         const markerPath = `${folderPath}.complete`;
         yield io.rmRF(folderPath);
@@ -10505,7 +10505,7 @@ function _createToolPath(tool, version, arch) {
     });
 }
 function _completeToolPath(tool, version, arch) {
-    const folderPath = path.join(cacheRoot, tool, semver.clean(version) || version, arch || '');
+    const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || '');
     const markerPath = `${folderPath}.complete`;
     fs.writeFileSync(markerPath, '');
     core.debug('finished caching tool');
@@ -10542,6 +10542,31 @@ function _evaluateVersions(versions, versionSpec) {
     }
     return version;
 }
+/**
+ * Gets RUNNER_TOOL_CACHE
+ */
+function _getCacheDirectory() {
+    const cacheDirectory = process.env['RUNNER_TOOL_CACHE'] || '';
+    assert_1.ok(cacheDirectory, 'Expected RUNNER_TOOL_CACHE to be defined');
+    return cacheDirectory;
+}
+/**
+ * Gets RUNNER_TEMP
+ */
+function _getTempDirectory() {
+    const tempDirectory = process.env['RUNNER_TEMP'] || '';
+    assert_1.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
+    return tempDirectory;
+}
+/**
+ * Gets a global variable
+ */
+function _getGlobal(key, defaultValue) {
+    /* eslint-disable @typescript-eslint/no-explicit-any */
+    const value = global[key];
+    /* eslint-enable @typescript-eslint/no-explicit-any */
+    return value !== undefined ? value : defaultValue;
+}
 //# sourceMappingURL=tool-cache.js.map
 
 /***/ }),
@@ -12091,8 +12116,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
     return result;
 };
 Object.defineProperty(exports, "__esModule", { value: true });
-// Load tempDirectory before it gets wiped by tool-cache
-let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
+const assert = __importStar(__webpack_require__(357));
 const core = __importStar(__webpack_require__(470));
 const hc = __importStar(__webpack_require__(539));
 const io = __importStar(__webpack_require__(1));
@@ -12102,22 +12126,6 @@ const path = __importStar(__webpack_require__(622));
 const semver = __importStar(__webpack_require__(280));
 let osPlat = os.platform();
 let osArch = translateArchToDistUrl(os.arch());
-if (!tempDirectory) {
-    let baseLocation;
-    if (process.platform === 'win32') {
-        // On windows use the USERPROFILE env variable
-        baseLocation = process.env['USERPROFILE'] || 'C:\\';
-    }
-    else {
-        if (process.platform === 'darwin') {
-            baseLocation = '/Users';
-        }
-        else {
-            baseLocation = '/home';
-        }
-    }
-    tempDirectory = path.join(baseLocation, 'actions', 'temp');
-}
 function getNode(versionSpec) {
     return __awaiter(this, void 0, void 0, function* () {
         // check cache
@@ -12276,8 +12284,10 @@ function acquireNode(version) {
 function acquireNodeFromFallbackLocation(version) {
     return __awaiter(this, void 0, void 0, function* () {
         // Create temporary folder to download in to
-        let tempDownloadFolder = 'temp_' + Math.floor(Math.random() * 2000000000);
-        let tempDir = path.join(tempDirectory, tempDownloadFolder);
+        const tempDownloadFolder = 'temp_' + Math.floor(Math.random() * 2000000000);
+        const tempDirectory = process.env['RUNNER_TEMP'] || '';
+        assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
+        const tempDir = path.join(tempDirectory, tempDownloadFolder);
         yield io.mkdirP(tempDir);
         let exeUrl;
         let libUrl;
@@ -15815,6 +15825,83 @@ function onceStrict (fn) {
 }
 
 
+/***/ }),
+
+/***/ 979:
+/***/ (function(__unusedmodule, exports, __webpack_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const core = __importStar(__webpack_require__(470));
+/**
+ * Internal class for retries
+ */
+class RetryHelper {
+    constructor(maxAttempts, minSeconds, maxSeconds) {
+        if (maxAttempts < 1) {
+            throw new Error('max attempts should be greater than or equal to 1');
+        }
+        this.maxAttempts = maxAttempts;
+        this.minSeconds = Math.floor(minSeconds);
+        this.maxSeconds = Math.floor(maxSeconds);
+        if (this.minSeconds > this.maxSeconds) {
+            throw new Error('min seconds should be less than or equal to max seconds');
+        }
+    }
+    execute(action, isRetryable) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let attempt = 1;
+            while (attempt < this.maxAttempts) {
+                // Try
+                try {
+                    return yield action();
+                }
+                catch (err) {
+                    if (isRetryable && !isRetryable(err)) {
+                        throw err;
+                    }
+                    core.info(err.message);
+                }
+                // Sleep
+                const seconds = this.getSleepAmount();
+                core.info(`Waiting ${seconds} seconds before trying again`);
+                yield this.sleep(seconds);
+                attempt++;
+            }
+            // Last attempt
+            return yield action();
+        });
+    }
+    getSleepAmount() {
+        return (Math.floor(Math.random() * (this.maxSeconds - this.minSeconds + 1)) +
+            this.minSeconds);
+    }
+    sleep(seconds) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return new Promise(resolve => setTimeout(resolve, seconds * 1000));
+        });
+    }
+}
+exports.RetryHelper = RetryHelper;
+//# sourceMappingURL=retry-helper.js.map
+
 /***/ }),
 
 /***/ 986:
diff --git a/package-lock.json b/package-lock.json
index 29fbac4c..a4b0fc81 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -40,9 +40,9 @@
       "integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
     },
     "@actions/tool-cache": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.3.1.tgz",
-      "integrity": "sha512-sKoEJv0/c7WzjPEq2PO12Sc8QdEp58XIBHMm3c4lUn/iZWgLz9HBeCuFGpLQjDvXJNfLZ4g+WD+rMjgOmpH4Ag==",
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.3.3.tgz",
+      "integrity": "sha512-AFVyTLcIxusDVI1gMhbZW8m/On7YNJG+xYaxorV+qic+f7lO7h37aT2mfzxqAq7mwHxtP1YlVFNrXe9QDf/bPg==",
       "requires": {
         "@actions/core": "^1.2.0",
         "@actions/exec": "^1.0.0",
@@ -738,9 +738,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.1.1",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
-          "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         }
       }
@@ -3484,9 +3484,9 @@
       }
     },
     "kind-of": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-      "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
       "dev": true
     },
     "kleur": {
diff --git a/package.json b/package.json
index fd0541fe..0321d497 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
     "@actions/github": "^1.1.0",
     "@actions/http-client": "^1.0.6",
     "@actions/io": "^1.0.2",
-    "@actions/tool-cache": "^1.3.1",
+    "@actions/tool-cache": "^1.3.3",
     "semver": "^6.1.1"
   },
   "devDependencies": {
diff --git a/src/installer.ts b/src/installer.ts
index 25c908a7..1265ed85 100644
--- a/src/installer.ts
+++ b/src/installer.ts
@@ -1,5 +1,3 @@
-// Load tempDirectory before it gets wiped by tool-cache
-let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
 import * as assert from 'assert';
 import * as core from '@actions/core';
 import * as hc from '@actions/http-client';
@@ -12,21 +10,6 @@ import * as semver from 'semver';
 let osPlat: string = os.platform();
 let osArch: string = translateArchToDistUrl(os.arch());
 
-if (!tempDirectory) {
-  let baseLocation;
-  if (process.platform === 'win32') {
-    // On windows use the USERPROFILE env variable
-    baseLocation = process.env['USERPROFILE'] || 'C:\\';
-  } else {
-    if (process.platform === 'darwin') {
-      baseLocation = '/Users';
-    } else {
-      baseLocation = '/home';
-    }
-  }
-  tempDirectory = path.join(baseLocation, 'actions', 'temp');
-}
-
 //
 // Node versions interface
 // see https://nodejs.org/dist/index.json
@@ -206,9 +189,11 @@ async function acquireNodeFromFallbackLocation(
   version: string
 ): Promise<string> {
   // Create temporary folder to download in to
-  let tempDownloadFolder: string =
+  const tempDownloadFolder: string =
     'temp_' + Math.floor(Math.random() * 2000000000);
-  let tempDir: string = path.join(tempDirectory, tempDownloadFolder);
+  const tempDirectory = process.env['RUNNER_TEMP'] || '';
+  assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
+  const tempDir: string = path.join(tempDirectory, tempDownloadFolder);
   await io.mkdirP(tempDir);
   let exeUrl: string;
   let libUrl: string;