diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4d259de..61e3ec0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -3,6 +3,20 @@ on: push: branches: ['**'] jobs: + lint: + name: Lint with ESLint / Prettier + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup node + uses: actions/setup-node@v1 + with: + node-version: '12' + - name: Run ESLint + run: | + npm install + npm run lint test: strategy: matrix: diff --git a/.huskyrc.js b/.huskyrc.js index a0ecbeb..4fb9348 100644 --- a/.huskyrc.js +++ b/.huskyrc.js @@ -2,6 +2,6 @@ const tasks = commands => commands.join(' && '); module.exports = { hooks: { - 'pre-commit': tasks(['npm run build', 'npm run format', 'git add .']), + 'pre-commit': tasks(['npm run build', 'npm run lint', 'git add dist/']), }, }; diff --git a/.prettierrc.js b/.prettierrc.js index 812585d..bbe2439 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,6 +1,12 @@ module.exports = { + printWidth: 120, + tabWidth: 2, + useTabs: false, + semi: true, singleQuote: true, quoteProps: 'as-needed', trailingComma: 'all', + bracketSpacing: true, arrowParens: 'avoid', + endOfLine: 'lf' }; diff --git a/.standard-commitrc.json b/.standard-commitrc.json new file mode 100644 index 0000000..b9d8c07 --- /dev/null +++ b/.standard-commitrc.json @@ -0,0 +1,17 @@ +{ + "types": [ + "feat", + "fix", + "chore", + "build", + "ci", + "docs", + "perf", + "refactor", + "revert", + "style", + "test" + ], + "promptScope": "suggest", + "scopes": "staged" +} diff --git a/README.md b/README.md index c00da21..a3840ae 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,9 @@ So we chose to create a JavaScript action to fix this problem, also adding addit authentication with Google Cloud Container Registry. Update [2019/01/27]: The [GoogleCloudPlatform official GitHub organization][2.4] has released an official -[setup-gcloud][2.5] action. Compared to Mathrix's one, we provide some additional automation tasks, such as project -guessing and automatic Docker Configuration. +[setup-gcloud][2.5] action. +Compared to Mathrix's one, we provide some additional automation tasks, such as project id discovery and automatic +Docker Configuration. [2.1]: https://github.com/actions/gcloud [2.2]: https://github.com/actions/gcloud/tree/master/auth @@ -38,8 +39,8 @@ guessing and automatic Docker Configuration. ## Usage ### Supported operating systems -This action currently supports Ubuntu, Mac-OS and Windows based systems. The supported operating systems matrix is -the following: +This action currently supports Ubuntu, Mac-OS and Windows based systems. +The supported operating system matrix is the following: | Operating system | Status | |------------------|-------| @@ -56,15 +57,16 @@ the following: | `service-account-key` | `string` (base64) | `''` | | `project` | `'auto'` / `'none'` / `string` | `'auto'` | | `components` | `string` | `''` | -| `configure-docker` | `true` / `false` | `false` | +| `configure-docker` | `'true'` / `'false'` | `'false'` | #### `version` -If you need a precise version of the Google Cloud SDK, you may provide this input. We strongly advise you to do so -since using the latest version may break your workflow if Google release a breaking version. +If you need a precise version of the Google Cloud SDK, you may provide this input. +We strongly advise you to do so since using the latest version may break your workflow if Google release a breaking +version. #### `service-account-key` -To authenticate the SDK, you may provide a **base64-encoded** service account JSON key. In order to secure you workflow, -use GitHub Actions [secrets][3.3]. +To authenticate the SDK, you may provide a **base64-encoded** service account JSON key. +In order to secure you workflow, use GitHub Actions [secrets][3.3]. [3.3]: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets @@ -74,14 +76,14 @@ By default, if you provide a `service-account-key`, the action will use it to de - If you want to specify a different project (for example, in case of cross-project interaction), you may explicitly specify your project ID here. - If you want to disable the project configuration and provide your project ID later in your workflow, set this input -to `none`. +to `'none'`. #### `components` If you want to install additional SDK components, you may provide them in this input. #### `configure-docker` If you want to push an image to the Google Container Registry, you may authenticate the Docker agent by setting the -input to true. +input to `'true'`. ## Examples @@ -91,8 +93,9 @@ See [action.yml](action.yml) for details. ```yaml - uses: mathrix-education/setup-gcloud@master ``` -By default, the minimal example will install the latest Google Cloud SDK. Because no service account key was provided -you will have to authenticate the SDK yourself (for example, with [`gcloud auth activate-service-account`][4.1]). +By default, the minimal example will install the latest Google Cloud SDK. +Because no service account key was provided you will have to authenticate the SDK yourself (for example, with +[`gcloud auth activate-service-account`][4.1]). [4.1]: https://cloud.google.com/sdk/gcloud/reference/auth/activate-service-account @@ -105,14 +108,14 @@ you will have to authenticate the SDK yourself (for example, with [`gcloud auth service-account-key: ${{ secrets.GCLOUD_AUTH }} # base64-encoded service account JSON key confgure-docker: true ``` -In this example, you provide a service account key. The action automatically download the latest version of the SDK and -authenticate using your key. +In this example, you provide a service account key. +The action automatically download the latest version of the SDK and authenticates using your key. Then using the field `"project_id"` of your key, we will set the default project using `gcloud config set project {project}`, so you do not have to do it later. Finally, because you may want to build a Docker image and upload it to the [Google Container Registry][4.2], the action -will configure Docker to allow the upload of your image. Make sure that the service account has the correct rights to -write on the bucket linked to the registry. +will configure Docker to allow the upload of your image. +Make sure the service account has the correct rights to write on the bucket linked to the registry. [4.2]: https://cloud.google.com/container-registry/ diff --git a/dist/index.js b/dist/index.js index 36e9184..ae2c5fc 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3071,6 +3071,13 @@ exports.setFailed = setFailed; //----------------------------------------------------------------------- // Logging Commands //----------------------------------------------------------------------- +/** + * Gets whether Actions Step Debug is on or not + */ +function isDebug() { + return process.env['RUNNER_DEBUG'] === '1'; +} +exports.isDebug = isDebug; /** * Writes debug message to user log * @param message debug message @@ -3202,9 +3209,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}`); @@ -3215,31 +3225,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 * @@ -3249,52 +3234,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 * @@ -3384,14 +3388,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]; @@ -3552,7 +3559,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}`); @@ -3574,7 +3581,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) { @@ -3593,7 +3600,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; @@ -3601,7 +3608,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); @@ -3611,7 +3618,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'); @@ -3648,6 +3655,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 /***/ }), @@ -4437,6 +4469,13 @@ module.exports = require("fs"); /***/ }), +/***/ 794: +/***/ (function(module) { + +module.exports = require("stream"); + +/***/ }), + /***/ 826: /***/ (function(module, __unusedexports, __webpack_require__) { @@ -4587,14 +4626,37 @@ async function gcloud(args, options = undefined) { +/** + * Configure the default Google Cloud project. + * @param projectId + */ +function configureProject(projectId) { + return gcloud(['config', 'set', 'project', projectId]); +} +/** + * Configure the default Google Cloud project from the GitHub inputs. + */ +async function configureProjectFromInput() { + if (!['', 'none', 'auto'].includes(Object(core.getInput)('project'))) { + return await configureProject(Object(core.getInput)('project')); + } + else { + return; + } +} +/** + * Configure Docker credentials for Google Cloud Registry + */ +async function configureDocker() { + await gcloud(['auth', 'configure-docker']); +} /** * Authenticate the Google Cloud SDK. */ async function authenticate() { // If service account key is not provided, skip the authentication if (!Object(core.getInput)('service-account-key')) { - Object(core.warning)('No service-account-key input was passed. If it is intentional, you can ' + - 'safely ignore this warning.'); + Object(core.warning)('No service-account-key input was passed. If it is intentional, you can safely ignore this warning.'); await configureProjectFromInput(); } // Write the service account key @@ -4603,16 +4665,11 @@ async function authenticate() { const serviceAccountKeyPath = Object(external_path_.resolve)(process.cwd(), 'gcloud.json'); Object(external_fs_.writeFileSync)(serviceAccountKeyPath, serviceAccountKeyJson); // Activate the service account - await gcloud([ - 'auth', - 'activate-service-account', - `--key-file=${serviceAccountKeyPath}`, - ]); + await gcloud(['auth', 'activate-service-account', `--key-file=${serviceAccountKeyPath}`]); // Remove the service account key Object(external_fs_.unlinkSync)(serviceAccountKeyPath); // Configure the default project - if (Object(core.getInput)('project') === 'auto' && - Object(core.getInput)('service-account-key') !== '') { + if (Object(core.getInput)('project') === 'auto' && Object(core.getInput)('service-account-key') !== '') { // Project will be read from the service account key const serviceAccountKey = JSON.parse(serviceAccountKeyJson.toString()); if (serviceAccountKey.hasOwnProperty('project_id')) { @@ -4632,30 +4689,6 @@ async function authenticate() { await configureDocker(); } } -/** - * Configure the default Google Cloud project. - * @param projectId - */ -function configureProject(projectId) { - return gcloud(['config', 'set', 'project', projectId]); -} -/** - * Configure the default Google Cloud project from the GitHub inputs. - */ -async function configureProjectFromInput() { - if (!['', 'none', 'auto'].includes(Object(core.getInput)('project'))) { - return await configureProject(Object(core.getInput)('project')); - } - else { - return; - } -} -/** - * Configure Docker credentials for Google Cloud Registry - */ -async function configureDocker() { - await gcloud(['auth', 'configure-docker']); -} // EXTERNAL MODULE: ./node_modules/@actions/tool-cache/lib/tool-cache.js var tool_cache = __webpack_require__(533); @@ -4831,6 +4864,83 @@ function checkBypass(reqUrl) { exports.checkBypass = checkBypass; +/***/ }), + +/***/ 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 c528fbf..dd2b36d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { "name": "@mathrix-education/setup-gcloud", - "version": "1.0.1", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@actions/core": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.2.tgz", - "integrity": "sha512-IbCx7oefq+Gi6FWbSs2Fnw8VkEI6Y4gvjrYprY3RV//ksq/KPMlClOerJ4jRosyal6zkUIc8R9fS/cpRMlGClg==" + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.3.tgz", + "integrity": "sha512-Wp4xnyokakM45Uuj4WLUxdsa8fJjKVl1fDTsPbTEcTcuu0Nb26IPQbOtjmnfaCPGcaoPOOqId8H9NapZ8gii4w==" }, "@actions/exec": { "version": "1.0.3", @@ -31,9 +31,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", @@ -82,9 +82,9 @@ "dev": true }, "@types/node": { - "version": "12.12.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.29.tgz", - "integrity": "sha512-yo8Qz0ygADGFptISDj3pOC9wXfln/5pQaN/ysDIzOaAWXt73cNHmtEC8zSO2Y+kse/txmwIAJzkYZ5fooaS5DQ==", + "version": "12.12.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.30.tgz", + "integrity": "sha512-sz9MF/zk6qVr3pAnM0BSQvYIBK44tS75QC5N+VbWSE4DjCV/pJ+UzCW/F+vVnl7TkOPcuwQureKNtSSwjBTaMg==", "dev": true }, "@types/normalize-package-data": { @@ -94,12 +94,12 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.21.0.tgz", - "integrity": "sha512-b5jjjDMxzcjh/Sbjuo7WyhrQmVJg0WipTHQgXh5Xwx10uYm6nPWqN1WGOsaNq4HR3Zh4wUx4IRQdDkCHwyewyw==", + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.24.0.tgz", + "integrity": "sha512-wJRBeaMeT7RLQ27UQkDFOu25MqFOBus8PtOa9KaT5ZuxC1kAsd7JEHqWt4YXuY9eancX0GK9C68i5OROnlIzBA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.21.0", + "@typescript-eslint/experimental-utils": "2.24.0", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -107,32 +107,32 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz", - "integrity": "sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA==", + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.24.0.tgz", + "integrity": "sha512-DXrwuXTdVh3ycNCMYmWhUzn/gfqu9N0VzNnahjiDJvcyhfBy4gb59ncVZVxdp5XzBC77dCncu0daQgOkbvPwBw==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.21.0", + "@typescript-eslint/typescript-estree": "2.24.0", "eslint-scope": "^5.0.0" } }, "@typescript-eslint/parser": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.21.0.tgz", - "integrity": "sha512-VrmbdrrrvvI6cPPOG7uOgGUFXNYTiSbnRq8ZMyuGa4+qmXJXVLEEz78hKuqupvkpwJQNk1Ucz1TenrRP90gmBg==", + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.24.0.tgz", + "integrity": "sha512-H2Y7uacwSSg8IbVxdYExSI3T7uM1DzmOn2COGtCahCC3g8YtM1xYAPi2MAHyfPs61VKxP/J/UiSctcRgw4G8aw==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.21.0", - "@typescript-eslint/typescript-estree": "2.21.0", + "@typescript-eslint/experimental-utils": "2.24.0", + "@typescript-eslint/typescript-estree": "2.24.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz", - "integrity": "sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw==", + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.24.0.tgz", + "integrity": "sha512-RJ0yMe5owMSix55qX7Mi9V6z2FDuuDpN6eR5fzRJrp+8in9UF41IGNQHbg5aMK4/PjVaEQksLvz0IA8n+Mr/FA==", "dev": true, "requires": { "debug": "^4.1.1", @@ -1054,18 +1054,18 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "ms": { diff --git a/package.json b/package.json index 2dcf437..482f4e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mathrix-education/setup-gcloud", - "version": "1.1.0", + "version": "1.1.1", "description": "Install the Google Cloud SDK in your GitHub Actions workflow.", "keywords": [ "github-actions", @@ -24,20 +24,21 @@ "url": "git+https://github.com/mathrix-education/setup-gcloud.git" }, "scripts": { - "format": "prettier --write \"src/**/*.ts\" \"*.js\"", + "lint": "eslint \"src/**\"", + "lint:fix": "eslint --fix \"src/**\"", "build": "ncc build src/install.ts" }, "dependencies": { - "@actions/core": "^1.2.2", + "@actions/core": "^1.2.3", "@actions/exec": "^1.0.3", - "@actions/tool-cache": "^1.3.1", + "@actions/tool-cache": "^1.3.3", "original-fs": "^1.1.0", "typescript": "^3.8.3" }, "devDependencies": { - "@types/node": "^12.12.29", - "@typescript-eslint/eslint-plugin": "^2.21.0", - "@typescript-eslint/parser": "^2.21.0", + "@types/node": "^12.12.30", + "@typescript-eslint/eslint-plugin": "^2.24.0", + "@typescript-eslint/parser": "^2.24.0", "@zeit/ncc": "^0.21.1", "eslint": "^6.8.0", "eslint-config-prettier": "^6.10.0", diff --git a/src/authenticate.ts b/src/authenticate.ts index 3079307..2ab38a9 100644 --- a/src/authenticate.ts +++ b/src/authenticate.ts @@ -3,48 +3,59 @@ import { unlinkSync, writeFileSync } from 'fs'; import { resolve } from 'path'; import { gcloud } from './utils'; +/** + * Configure the default Google Cloud project. + * @param projectId + */ +function configureProject(projectId: string): Promise { + return gcloud(['config', 'set', 'project', projectId]); +} + +/** + * Configure the default Google Cloud project from the GitHub inputs. + */ +async function configureProjectFromInput(): Promise { + if (!['', 'none', 'auto'].includes(core.getInput('project'))) { + return await configureProject(core.getInput('project')); + } else { + return; + } +} + +/** + * Configure Docker credentials for Google Cloud Registry + */ +async function configureDocker(): Promise { + await gcloud(['auth', 'configure-docker']); +} + /** * Authenticate the Google Cloud SDK. */ export async function authenticate(): Promise { // If service account key is not provided, skip the authentication if (!core.getInput('service-account-key')) { - core.warning( - 'No service-account-key input was passed. If it is intentional, you can ' + - 'safely ignore this warning.', - ); + core.warning('No service-account-key input was passed. If it is intentional, you can safely ignore this warning.'); await configureProjectFromInput(); } // Write the service account key const serviceAccountKeyBase64 = core.getInput('service-account-key'); - const serviceAccountKeyJson = Buffer.from( - serviceAccountKeyBase64, - 'base64', - ).toString(); + const serviceAccountKeyJson = Buffer.from(serviceAccountKeyBase64, 'base64').toString(); const serviceAccountKeyPath = resolve(process.cwd(), 'gcloud.json'); writeFileSync(serviceAccountKeyPath, serviceAccountKeyJson); // Activate the service account - await gcloud([ - 'auth', - 'activate-service-account', - `--key-file=${serviceAccountKeyPath}`, - ]); + await gcloud(['auth', 'activate-service-account', `--key-file=${serviceAccountKeyPath}`]); // Remove the service account key unlinkSync(serviceAccountKeyPath); // Configure the default project - if ( - core.getInput('project') === 'auto' && - core.getInput('service-account-key') !== '' - ) { + if (core.getInput('project') === 'auto' && core.getInput('service-account-key') !== '') { // Project will be read from the service account key - const serviceAccountKey: { project_id: string } = JSON.parse( - serviceAccountKeyJson.toString(), - ); + const serviceAccountKey: { project_id: string } = JSON.parse(serviceAccountKeyJson.toString()); if (serviceAccountKey.hasOwnProperty('project_id')) { // If key has a project_id field, use it to set the default project @@ -64,29 +75,3 @@ export async function authenticate(): Promise { await configureDocker(); } } - -/** - * Configure the default Google Cloud project. - * @param projectId - */ -function configureProject(projectId: string): Promise { - return gcloud(['config', 'set', 'project', projectId]); -} - -/** - * Configure the default Google Cloud project from the GitHub inputs. - */ -async function configureProjectFromInput(): Promise { - if (!['', 'none', 'auto'].includes(core.getInput('project'))) { - return await configureProject(core.getInput('project')); - } else { - return; - } -} - -/** - * Configure Docker credentials for Google Cloud Registry - */ -async function configureDocker() { - await gcloud(['auth', 'configure-docker']); -} diff --git a/src/constants.ts b/src/constants.ts index a306de2..752fe06 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,8 +2,5 @@ import { resolve } from 'path'; export const INSTALL_DIRECTORY = 'google-cloud-sdk'; export const UBUNTU_INSTALL_PATH = `/usr/lib/${INSTALL_DIRECTORY}`; -export const MACOS_INSTALL_PATH = resolve( - process.env.HOME ?? process.cwd(), - INSTALL_DIRECTORY, -); +export const MACOS_INSTALL_PATH = resolve(process.env.HOME ?? process.cwd(), INSTALL_DIRECTORY); export const WINDOWS_INSTALL_PATH = `C:\\Program Files\\${INSTALL_DIRECTORY}`; diff --git a/src/download.ts b/src/download.ts index 1231e52..7fc6731 100644 --- a/src/download.ts +++ b/src/download.ts @@ -27,8 +27,6 @@ export async function download(): Promise { } } else { // Should never be reached - core.setFailed( - `Unexpected extension (expected zip or tar.gz), but got ${downloadLink}`, - ); + core.setFailed(`Unexpected extension (expected zip or tar.gz), but got ${downloadLink}`); } } diff --git a/src/install.ts b/src/install.ts index 76e8716..1fe0e94 100644 --- a/src/install.ts +++ b/src/install.ts @@ -7,7 +7,7 @@ import { setup } from './setup'; * Install the Google Cloud SDK. */ try { - (async () => { + (async (): Promise => { await download(); await setup(); await authenticate(); diff --git a/src/setup.ts b/src/setup.ts index 4fc4fb9..87e8c7a 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -9,10 +9,7 @@ import { getCloudSDKDirectory, isMacOS, isUbuntu, isWindows } from './utils'; */ export async function setup(): Promise { const installScriptExtension = isWindows() ? 'bat' : 'sh'; - const installScript = resolve( - getCloudSDKDirectory(), - `install.${installScriptExtension}`, - ); + const installScript = resolve(getCloudSDKDirectory(), `install.${installScriptExtension}`); const args = [ '--usage-reporting=false', diff --git a/src/utils.ts b/src/utils.ts index 34438d1..3653d7b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,12 +2,7 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; import { ExecOptions } from '@actions/exec/lib/interfaces'; import { resolve } from 'path'; -import { - INSTALL_DIRECTORY, - MACOS_INSTALL_PATH, - UBUNTU_INSTALL_PATH, - WINDOWS_INSTALL_PATH, -} from './constants'; +import { MACOS_INSTALL_PATH, UBUNTU_INSTALL_PATH, WINDOWS_INSTALL_PATH } from './constants'; /** * Check if the runner is Windows-based. @@ -72,22 +67,12 @@ export function getDownloadLink(): string { * @param args The gcloud args * @param options The command options */ -export async function gcloud( - args: string[], - options: ExecOptions | undefined = undefined, -): Promise { - let gcloudPath = resolve( - getCloudSDKDirectory(), - 'bin', - 'gcloud' + (isWindows() ? '.cmd' : ''), - ); +export async function gcloud(args: string[], options: ExecOptions | undefined = undefined): Promise { + let gcloudPath = resolve(getCloudSDKDirectory(), 'bin', 'gcloud' + (isWindows() ? '.cmd' : '')); if (isWindows()) { // Windows installation directory is C:\Program Files and thus need to be escaped - gcloudPath = gcloudPath.replace( - getCloudSDKDirectory(), - `"${getCloudSDKDirectory()}"`, - ); + gcloudPath = gcloudPath.replace(getCloudSDKDirectory(), `"${getCloudSDKDirectory()}"`); } args.unshift('--quiet'); // Add quiet to all commands