From 5abf3cab2bbe8d4b81bac800646f5d75c0a86dd1 Mon Sep 17 00:00:00 2001 From: shlomp Date: Tue, 29 Dec 2020 00:55:18 +0200 Subject: [PATCH 1/7] Added good flow unittest --- .vscode/extensions.json | 11 ++ __mocks__/@actions/core.ts | 9 ++ __mocks__/@actions/tool-cache.ts | 5 + dist/index.js | 30 ++--- index.ts | 4 +- jest.config.js | 8 ++ lib/terratag-action.spec.ts | 73 ++++++++++++ lib/terratag-action.ts | 52 ++++---- package-lock.json | 196 +++++++++++++++++++++++-------- package.json | 11 +- prettier.config.js | 4 + 11 files changed, 301 insertions(+), 102 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 __mocks__/@actions/core.ts create mode 100644 __mocks__/@actions/tool-cache.ts create mode 100644 jest.config.js create mode 100644 lib/terratag-action.spec.ts create mode 100644 prettier.config.js diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..b023fa8 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "christian-kohler.npm-intellisense", + "dbaeumer.vscode-eslint", + "eg2.vscode-npm-script", + "esbenp.prettier-vscode", + "lannonbr.vscode-js-annotations", + "ms-vscode.vscode-typescript-tslint-plugin", + "orta.vscode-jest" + ] +} \ No newline at end of file diff --git a/__mocks__/@actions/core.ts b/__mocks__/@actions/core.ts new file mode 100644 index 0000000..75a842f --- /dev/null +++ b/__mocks__/@actions/core.ts @@ -0,0 +1,9 @@ +const self = { + error: jest.fn(), + info: jest.fn(), + debug: jest.fn(), + warn: jest.fn(), + getInput: jest.fn(), + addPath: jest.fn(), +} +export default self; \ No newline at end of file diff --git a/__mocks__/@actions/tool-cache.ts b/__mocks__/@actions/tool-cache.ts new file mode 100644 index 0000000..20a90aa --- /dev/null +++ b/__mocks__/@actions/tool-cache.ts @@ -0,0 +1,5 @@ +const self = { + downloadTool: jest.fn(), + extractTar: jest.fn(), +} +export default self; \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index f95d0ac..8ebd1ec 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8700,8 +8700,8 @@ const tool_cache_1 = __importDefault(__webpack_require__(7784)); // return value in [amd64, 386, arm] function mapArch(arch) { const mappings = { - x32: '386', - x64: 'amd64' + x32: "386", + x64: "amd64", }; return mappings[arch] || arch; } @@ -8709,7 +8709,7 @@ function mapArch(arch) { // return value in [darwin, linux, windows] function mapOS(os) { const mappings = { - win32: 'windows' + win32: "windows", }; return mappings[os] || os; } @@ -8717,7 +8717,7 @@ function downloadCLI(url) { return __awaiter(this, void 0, void 0, function* () { core_1.default.debug(`Downloading Terratag CLI from ${url}`); const pathToCLITar = yield tool_cache_1.default.downloadTool(url); - core_1.default.debug('Extracting Terratag CLI zip file'); + core_1.default.debug("Extracting Terratag CLI zip file"); const pathToCLI = yield tool_cache_1.default.extractTar(pathToCLITar); core_1.default.debug(`Terratag CLI path is ${pathToCLI}.`); if (!pathToCLITar || !pathToCLI) { @@ -8728,7 +8728,7 @@ function downloadCLI(url) { } function latestVersion() { return __awaiter(this, void 0, void 0, function* () { - const response = yield axios_1.default.get('https://github.com/env0/terratag/releases'); + const response = yield axios_1.default.get("https://github.com/env0/terratag/releases"); if (response.status !== 200) { throw new Error(`Unable to fetch terratag releases: response ${response.status}: ${response.data}`); } @@ -8741,8 +8741,8 @@ function latestVersion() { }); } function cliArgsFromActionInputs() { - const cliArgs = [`-tags=${core_1.default.getInput('tags')}`]; - const dir = core_1.default.getInput('dir'); + const cliArgs = [`-tags=${core_1.default.getInput("tags")}`]; + const dir = core_1.default.getInput("dir"); if (dir) { cliArgs.push(`-dir=${dir}`); } @@ -8755,14 +8755,14 @@ function cliArgsFromActionInputs() { cliArgs.push(`-${flagName}=${value}`); } }; - boolFlag('skipTerratagFiles'); - boolFlag('verbose'); - boolFlag('rename'); + boolFlag("skipTerratagFiles"); + boolFlag("verbose"); + boolFlag("rename"); return cliArgs; } function terratagVersionFromActionInputs() { return __awaiter(this, void 0, void 0, function* () { - const version = core_1.default.getInput('terratagVersion'); + const version = core_1.default.getInput("terratagVersion"); if (version === "latest") { return yield latestVersion(); } @@ -8772,7 +8772,7 @@ function terratagVersionFromActionInputs() { function terratagVersionDownloadURL(version) { const osPlatform = os_1.default.platform(); const osArch = os_1.default.arch(); - if (osArch !== 'x64') { + if (osArch !== "x64") { throw new Error("Terratag action currently only supports x64/amd64"); } const platform = mapOS(osPlatform); @@ -8798,15 +8798,15 @@ function run() { console.info("Terratag installed, invoking"); yield new Promise((resolve, reject) => { const child = child_process_1.default.spawn(`${pathToCLI}/terratag`, cliArgs); - child.stdout.on('data', data => { + child.stdout.on("data", (data) => { console.info(data); core_1.default.info(data); }); - child.stderr.on('data', data => { + child.stderr.on("data", (data) => { console.error(data); core_1.default.error(data); }); - child.on('close', code => { + child.on("close", (code) => { if (code === 0) { resolve(); } diff --git a/index.ts b/index.ts index 0640fa7..db86fc0 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,6 @@ -import core from '@actions/core'; +import core from "@actions/core"; -import terratagAction from './lib/terratag-action'; +import terratagAction from "./lib/terratag-action"; (async () => { try { diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..3f1a066 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testPathIgnorePatterns: [ + "/dist/", + "/node_modules/" + ] +}; diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts new file mode 100644 index 0000000..2d00701 --- /dev/null +++ b/lib/terratag-action.spec.ts @@ -0,0 +1,73 @@ +jest.mock("axios"); +jest.mock("child_process"); +import axios from "axios"; +const mockedAxios = axios as jest.Mocked; +import childProcess from "child_process"; +const mockedChildProcess = childProcess as jest.Mocked; +import core from "@actions/core"; +const mockedCore = core as jest.Mocked; +import tc from "@actions/tool-cache"; +const mockedTC = tc as jest.Mocked; + +import run from "./terratag-action"; + +test("simple end to end, latest terratag", async () => { + jest.resetAllMocks(); + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: "latest", tags: JSON.stringify({ a: "b" }) }; + return inputs[name]; + }); + mockedAxios.get.mockResolvedValue({ + status: 200, + data: `href="/env0/terratag/releases/tag/v1.2.3"`, + }); + mockedTC.downloadTool.mockResolvedValue("FAKE PATH FOR DOWNLOADED TOOL TAR"); + mockedTC.extractTar.mockResolvedValue("FAKE PATH FOR EXTRACTED"); + const spawn = { + stdout: { on: jest.fn() }, + stderr: { on: jest.fn() }, + on: jest.fn(), + }; + spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { + expect(eventName).toBe("close"); + callback(0); + }); + mockedChildProcess.spawn.mockReturnValue(spawn as any); + await run(); + expect(mockedCore.addPath.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED"]]); + expect(mockedAxios.get.mock.calls).toEqual([["https://github.com/env0/terratag/releases"]]); + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ["https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz"], + ]); + expect(mockedTC.extractTar.mock.calls).toEqual([["FAKE PATH FOR DOWNLOADED TOOL TAR"]]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED/terratag", ['-tags={"a":"b"}']]]); +}); + +test("simple end to end, specific terratag", async () => { + jest.resetAllMocks(); + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: "5.6.7", tags: JSON.stringify({ a: "b" }) }; + return inputs[name]; + }); + mockedAxios.get.mockRejectedValue("Should not be called"); + mockedTC.downloadTool.mockResolvedValue("FAKE PATH FOR DOWNLOADED TOOL TAR"); + mockedTC.extractTar.mockResolvedValue("FAKE PATH FOR EXTRACTED"); + const spawn = { + stdout: { on: jest.fn() }, + stderr: { on: jest.fn() }, + on: jest.fn(), + }; + spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { + expect(eventName).toBe("close"); + callback(0); + }); + mockedChildProcess.spawn.mockReturnValue(spawn as any); + await run(); + expect(mockedCore.addPath.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED"]]); + expect(mockedAxios.get.mock.calls).toEqual([]); + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ["https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz"], + ]); + expect(mockedTC.extractTar.mock.calls).toEqual([["FAKE PATH FOR DOWNLOADED TOOL TAR"]]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED/terratag", ['-tags={"a":"b"}']]]); +}); diff --git a/lib/terratag-action.ts b/lib/terratag-action.ts index 9f882c3..88d59a8 100644 --- a/lib/terratag-action.ts +++ b/lib/terratag-action.ts @@ -1,15 +1,15 @@ -import os from 'os'; -import axios from 'axios'; -import childProcess from 'child_process'; -import core from '@actions/core'; -import tc from '@actions/tool-cache'; +import os from "os"; +import axios from "axios"; +import childProcess from "child_process"; +import core from "@actions/core"; +import tc from "@actions/tool-cache"; // arch in [arm, x32, x64...] (https://nodejs.org/api/os.html#os_os_arch) // return value in [amd64, 386, arm] function mapArch(arch: string): string { - const mappings: {[key: string]: string} = { - x32: '386', - x64: 'amd64' + const mappings: { [key: string]: string } = { + x32: "386", + x64: "amd64", }; return mappings[arch] || arch; } @@ -17,8 +17,8 @@ function mapArch(arch: string): string { // os in [darwin, linux, win32...] (https://nodejs.org/api/os.html#os_os_platform) // return value in [darwin, linux, windows] function mapOS(os: string): string { - const mappings: {[key: string]: string} = { - win32: 'windows' + const mappings: { [key: string]: string } = { + win32: "windows", }; return mappings[os] || os; } @@ -27,7 +27,7 @@ async function downloadCLI(url: string): Promise { core.debug(`Downloading Terratag CLI from ${url}`); const pathToCLITar = await tc.downloadTool(url); - core.debug('Extracting Terratag CLI zip file'); + core.debug("Extracting Terratag CLI zip file"); const pathToCLI = await tc.extractTar(pathToCLITar); core.debug(`Terratag CLI path is ${pathToCLI}.`); @@ -39,7 +39,7 @@ async function downloadCLI(url: string): Promise { } async function latestVersion(): Promise { - const response = await axios.get('https://github.com/env0/terratag/releases'); + const response = await axios.get("https://github.com/env0/terratag/releases"); if (response.status !== 200) { throw new Error(`Unable to fetch terratag releases: response ${response.status}: ${response.data}`); } @@ -52,12 +52,12 @@ async function latestVersion(): Promise { } function cliArgsFromActionInputs(): string[] { - const cliArgs = [`-tags=${core.getInput('tags')}`]; - const dir = core.getInput('dir'); + const cliArgs = [`-tags=${core.getInput("tags")}`]; + const dir = core.getInput("dir"); if (dir) { cliArgs.push(`-dir=${dir}`); } - const boolFlag = (flagName:string) => { + const boolFlag = (flagName: string) => { const value = core.getInput(flagName); if (value) { if (value !== "true" && value !== "false") { @@ -65,15 +65,15 @@ function cliArgsFromActionInputs(): string[] { } cliArgs.push(`-${flagName}=${value}`); } - } - boolFlag('skipTerratagFiles'); - boolFlag('verbose'); - boolFlag('rename'); + }; + boolFlag("skipTerratagFiles"); + boolFlag("verbose"); + boolFlag("rename"); return cliArgs; } async function terratagVersionFromActionInputs(): Promise { - const version = core.getInput('terratagVersion'); + const version = core.getInput("terratagVersion"); if (version === "latest") { return await latestVersion(); } @@ -83,8 +83,8 @@ async function terratagVersionFromActionInputs(): Promise { function terratagVersionDownloadURL(version: string): string { const osPlatform = os.platform(); const osArch = os.arch(); - if (osArch !== 'x64') { - throw new Error("Terratag action currently only supports x64/amd64"); + if (osArch !== "x64") { + throw new Error("Terratag action currently only supports x64/amd64"); } const platform = mapOS(osPlatform); @@ -109,17 +109,17 @@ export default async function run(): Promise { core.addPath(pathToCLI); console.info("Terratag installed, invoking"); - await new Promise((resolve, reject)=>{ + await new Promise((resolve, reject) => { const child = childProcess.spawn(`${pathToCLI}/terratag`, cliArgs); - child.stdout.on('data', data=>{ + child.stdout.on("data", (data) => { console.info(data); core.info(data); }); - child.stderr.on('data', data=>{ + child.stderr.on("data", (data) => { console.error(data); core.error(data); }); - child.on('close', code=>{ + child.on("close", (code) => { if (code === 0) { resolve(); } else { diff --git a/package-lock.json b/package-lock.json index 1e3b8b4..02cee48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,12 +101,12 @@ } }, "@babel/generator": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz", - "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", + "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", "dev": true, "requires": { - "@babel/types": "^7.12.10", + "@babel/types": "^7.12.11", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -120,14 +120,14 @@ } }, "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", + "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-get-function-arity": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/types": "^7.12.11" } }, "@babel/helper-get-function-arity": { @@ -190,15 +190,15 @@ "dev": true }, "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", + "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/helper-member-expression-to-functions": "^7.12.7", + "@babel/helper-optimise-call-expression": "^7.12.10", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.11" } }, "@babel/helper-simple-access": { @@ -211,12 +211,12 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", + "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.11" } }, "@babel/helper-validator-identifier": { @@ -300,9 +300,9 @@ } }, "@babel/parser": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz", - "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -425,31 +425,50 @@ } }, "@babel/traverse": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz", - "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", + "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.10", - "@babel/types": "^7.12.10", + "@babel/code-frame": "^7.12.11", + "@babel/generator": "^7.12.11", + "@babel/helper-function-name": "^7.12.11", + "@babel/helper-split-export-declaration": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/types": "^7.12.12", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + } } }, "@babel/types": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz", - "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + } } }, "@bcoe/v8-coverage": { @@ -905,6 +924,16 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "26.0.19", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.19.tgz", + "integrity": "sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==", + "dev": true, + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -929,9 +958,9 @@ "dev": true }, "@types/prettier": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", - "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz", + "integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==", "dev": true }, "@types/stack-utils": { @@ -941,18 +970,18 @@ "dev": true }, "@types/yargs": { - "version": "15.0.11", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz", - "integrity": "sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==", + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz", + "integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, "@vercel/ncc": { @@ -1225,9 +1254,9 @@ } }, "babel-preset-current-node-syntax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz", - "integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -1354,6 +1383,15 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -4188,6 +4226,12 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.set": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", @@ -4227,6 +4271,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -6108,6 +6158,48 @@ "punycode": "^2.1.1" } }, + "ts-jest": { + "version": "26.4.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.4.4.tgz", + "integrity": "sha512-3lFWKbLxJm34QxyVNNCgXX1u4o/RV0myvA2y2Bxm46iGIjKlaY0own9gIckbjZJPn+WaJEnfPPJ20HHGpoq4yg==", + "dev": true, + "requires": { + "@types/jest": "26.x", + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^26.1.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } + } + }, "tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", @@ -6283,9 +6375,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz", - "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", + "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", diff --git a/package.json b/package.json index 11e756a..b6494f6 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "publisher": "env0", "main": "index.js", "scripts": { - "build": "ncc build index.ts --out dist" + "build": "ncc build index.ts --out dist", + "test": "npx jest" }, "keywords": [], "author": "", @@ -18,19 +19,15 @@ "axios": "^0.21.0" }, "devDependencies": { + "@types/jest": "^26.0.19", "@vercel/ncc": "^0.25.1", "husky": "^4.3.6", "jest": "^26.6.3", "nock": "^13.0.5", "semistandard": "^16.0.0", + "ts-jest": "^26.4.4", "typescript": "^4.1.3" }, - "jest": { - "testPathIgnorePatterns": [ - "/dist/", - "/node_modules/" - ] - }, "semistandard": { "ignore": [ "dist/**" diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..dbe3b11 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,4 @@ +module.exports = { + tabWidth: 2, + printWidth: 120 +}; From 720db5eaad42336abebf1118aaebef6c5f9a8546 Mon Sep 17 00:00:00 2001 From: shlomp Date: Tue, 29 Dec 2020 01:01:26 +0200 Subject: [PATCH 2/7] CI --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ package.json | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3f016bb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2-beta + with: + node-version: '12' + - name: Install dependencies + run: | + npm i + - name: Style check + run: | + npx prettier --check "*.ts" "lib/*.ts" + - name: Unit test + run: | + npm run test diff --git a/package.json b/package.json index b6494f6..8b7cfb5 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "main": "index.js", "scripts": { "build": "ncc build index.ts --out dist", - "test": "npx jest" + "test": "npx jest", + "style": "npx prettier --write *.ts lib/*.ts" }, "keywords": [], "author": "", From 362b2ce539769480326b799c37678bb024920e3f Mon Sep 17 00:00:00 2001 From: shlomp Date: Thu, 31 Dec 2020 09:47:10 +0200 Subject: [PATCH 3/7] New prettier conf --- .prettierrc | 11 +++++++ dist/index.js | 40 ++++++++++++------------- index.ts | 4 +-- lib/terratag-action.spec.ts | 60 ++++++++++++++++++------------------- lib/terratag-action.ts | 50 +++++++++++++++---------------- prettier.config.js | 4 --- 6 files changed, 88 insertions(+), 81 deletions(-) create mode 100644 .prettierrc delete mode 100644 prettier.config.js diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e82757e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "semi": true, + "singleQuote": true, + "printWidth": 120, + "trailingComma": "none", + "parser": "typescript", + "proseWrap": "preserve", + "quoteProps": "as-needed", + "jsxBracketSameLine": true, + "arrowParens": "avoid" +} diff --git a/dist/index.js b/dist/index.js index 8ebd1ec..560ef3d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8700,8 +8700,8 @@ const tool_cache_1 = __importDefault(__webpack_require__(7784)); // return value in [amd64, 386, arm] function mapArch(arch) { const mappings = { - x32: "386", - x64: "amd64", + x32: '386', + x64: 'amd64' }; return mappings[arch] || arch; } @@ -8709,7 +8709,7 @@ function mapArch(arch) { // return value in [darwin, linux, windows] function mapOS(os) { const mappings = { - win32: "windows", + win32: 'windows' }; return mappings[os] || os; } @@ -8717,7 +8717,7 @@ function downloadCLI(url) { return __awaiter(this, void 0, void 0, function* () { core_1.default.debug(`Downloading Terratag CLI from ${url}`); const pathToCLITar = yield tool_cache_1.default.downloadTool(url); - core_1.default.debug("Extracting Terratag CLI zip file"); + core_1.default.debug('Extracting Terratag CLI zip file'); const pathToCLI = yield tool_cache_1.default.extractTar(pathToCLITar); core_1.default.debug(`Terratag CLI path is ${pathToCLI}.`); if (!pathToCLITar || !pathToCLI) { @@ -8728,42 +8728,42 @@ function downloadCLI(url) { } function latestVersion() { return __awaiter(this, void 0, void 0, function* () { - const response = yield axios_1.default.get("https://github.com/env0/terratag/releases"); + const response = yield axios_1.default.get('https://github.com/env0/terratag/releases'); if (response.status !== 200) { throw new Error(`Unable to fetch terratag releases: response ${response.status}: ${response.data}`); } const regex = new RegExp('href="/env0/terratag/releases/tag/v(.{1,15})"'); const found = response.data.match(regex); if (!found) { - throw new Error("Unable to determine latest terratag version"); + throw new Error('Unable to determine latest terratag version'); } return found[1]; }); } function cliArgsFromActionInputs() { - const cliArgs = [`-tags=${core_1.default.getInput("tags")}`]; - const dir = core_1.default.getInput("dir"); + const cliArgs = [`-tags=${core_1.default.getInput('tags')}`]; + const dir = core_1.default.getInput('dir'); if (dir) { cliArgs.push(`-dir=${dir}`); } const boolFlag = (flagName) => { const value = core_1.default.getInput(flagName); if (value) { - if (value !== "true" && value !== "false") { + if (value !== 'true' && value !== 'false') { throw new Error(`${flagName} can only accept 'true' or 'false'`); } cliArgs.push(`-${flagName}=${value}`); } }; - boolFlag("skipTerratagFiles"); - boolFlag("verbose"); - boolFlag("rename"); + boolFlag('skipTerratagFiles'); + boolFlag('verbose'); + boolFlag('rename'); return cliArgs; } function terratagVersionFromActionInputs() { return __awaiter(this, void 0, void 0, function* () { - const version = core_1.default.getInput("terratagVersion"); - if (version === "latest") { + const version = core_1.default.getInput('terratagVersion'); + if (version === 'latest') { return yield latestVersion(); } return version; @@ -8772,8 +8772,8 @@ function terratagVersionFromActionInputs() { function terratagVersionDownloadURL(version) { const osPlatform = os_1.default.platform(); const osArch = os_1.default.arch(); - if (osArch !== "x64") { - throw new Error("Terratag action currently only supports x64/amd64"); + if (osArch !== 'x64') { + throw new Error('Terratag action currently only supports x64/amd64'); } const platform = mapOS(osPlatform); const arch = mapArch(osArch); @@ -8795,18 +8795,18 @@ function run() { core_1.default.info(`Successfully installed terratag ${version}`); // Add to path core_1.default.addPath(pathToCLI); - console.info("Terratag installed, invoking"); + console.info('Terratag installed, invoking'); yield new Promise((resolve, reject) => { const child = child_process_1.default.spawn(`${pathToCLI}/terratag`, cliArgs); - child.stdout.on("data", (data) => { + child.stdout.on('data', data => { console.info(data); core_1.default.info(data); }); - child.stderr.on("data", (data) => { + child.stderr.on('data', data => { console.error(data); core_1.default.error(data); }); - child.on("close", (code) => { + child.on('close', code => { if (code === 0) { resolve(); } diff --git a/index.ts b/index.ts index db86fc0..0640fa7 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,6 @@ -import core from "@actions/core"; +import core from '@actions/core'; -import terratagAction from "./lib/terratag-action"; +import terratagAction from './lib/terratag-action'; (async () => { try { diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts index 2d00701..c781d90 100644 --- a/lib/terratag-action.spec.ts +++ b/lib/terratag-action.spec.ts @@ -1,73 +1,73 @@ -jest.mock("axios"); -jest.mock("child_process"); -import axios from "axios"; +jest.mock('axios'); +jest.mock('child_process'); +import axios from 'axios'; const mockedAxios = axios as jest.Mocked; -import childProcess from "child_process"; +import childProcess from 'child_process'; const mockedChildProcess = childProcess as jest.Mocked; -import core from "@actions/core"; +import core from '@actions/core'; const mockedCore = core as jest.Mocked; -import tc from "@actions/tool-cache"; +import tc from '@actions/tool-cache'; const mockedTC = tc as jest.Mocked; -import run from "./terratag-action"; +import run from './terratag-action'; -test("simple end to end, latest terratag", async () => { +test('simple end to end, latest terratag', async () => { jest.resetAllMocks(); mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: "latest", tags: JSON.stringify({ a: "b" }) }; + const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; return inputs[name]; }); mockedAxios.get.mockResolvedValue({ status: 200, - data: `href="/env0/terratag/releases/tag/v1.2.3"`, + data: `href="/env0/terratag/releases/tag/v1.2.3"` }); - mockedTC.downloadTool.mockResolvedValue("FAKE PATH FOR DOWNLOADED TOOL TAR"); - mockedTC.extractTar.mockResolvedValue("FAKE PATH FOR EXTRACTED"); + mockedTC.downloadTool.mockResolvedValue('FAKE PATH FOR DOWNLOADED TOOL TAR'); + mockedTC.extractTar.mockResolvedValue('FAKE PATH FOR EXTRACTED'); const spawn = { stdout: { on: jest.fn() }, stderr: { on: jest.fn() }, - on: jest.fn(), + on: jest.fn() }; spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { - expect(eventName).toBe("close"); + expect(eventName).toBe('close'); callback(0); }); mockedChildProcess.spawn.mockReturnValue(spawn as any); await run(); - expect(mockedCore.addPath.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED"]]); - expect(mockedAxios.get.mock.calls).toEqual([["https://github.com/env0/terratag/releases"]]); + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); + expect(mockedAxios.get.mock.calls).toEqual([['https://github.com/env0/terratag/releases']]); expect(mockedTC.downloadTool.mock.calls).toEqual([ - ["https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz"], + ['https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz'] ]); - expect(mockedTC.extractTar.mock.calls).toEqual([["FAKE PATH FOR DOWNLOADED TOOL TAR"]]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED/terratag", ['-tags={"a":"b"}']]]); + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); -test("simple end to end, specific terratag", async () => { +test('simple end to end, specific terratag', async () => { jest.resetAllMocks(); mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: "5.6.7", tags: JSON.stringify({ a: "b" }) }; + const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; return inputs[name]; }); - mockedAxios.get.mockRejectedValue("Should not be called"); - mockedTC.downloadTool.mockResolvedValue("FAKE PATH FOR DOWNLOADED TOOL TAR"); - mockedTC.extractTar.mockResolvedValue("FAKE PATH FOR EXTRACTED"); + mockedAxios.get.mockRejectedValue('Should not be called'); + mockedTC.downloadTool.mockResolvedValue('FAKE PATH FOR DOWNLOADED TOOL TAR'); + mockedTC.extractTar.mockResolvedValue('FAKE PATH FOR EXTRACTED'); const spawn = { stdout: { on: jest.fn() }, stderr: { on: jest.fn() }, - on: jest.fn(), + on: jest.fn() }; spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { - expect(eventName).toBe("close"); + expect(eventName).toBe('close'); callback(0); }); mockedChildProcess.spawn.mockReturnValue(spawn as any); await run(); - expect(mockedCore.addPath.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED"]]); + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); expect(mockedAxios.get.mock.calls).toEqual([]); expect(mockedTC.downloadTool.mock.calls).toEqual([ - ["https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz"], + ['https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz'] ]); - expect(mockedTC.extractTar.mock.calls).toEqual([["FAKE PATH FOR DOWNLOADED TOOL TAR"]]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([["FAKE PATH FOR EXTRACTED/terratag", ['-tags={"a":"b"}']]]); + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); diff --git a/lib/terratag-action.ts b/lib/terratag-action.ts index 88d59a8..3758e8e 100644 --- a/lib/terratag-action.ts +++ b/lib/terratag-action.ts @@ -1,15 +1,15 @@ -import os from "os"; -import axios from "axios"; -import childProcess from "child_process"; -import core from "@actions/core"; -import tc from "@actions/tool-cache"; +import os from 'os'; +import axios from 'axios'; +import childProcess from 'child_process'; +import core from '@actions/core'; +import tc from '@actions/tool-cache'; // arch in [arm, x32, x64...] (https://nodejs.org/api/os.html#os_os_arch) // return value in [amd64, 386, arm] function mapArch(arch: string): string { const mappings: { [key: string]: string } = { - x32: "386", - x64: "amd64", + x32: '386', + x64: 'amd64' }; return mappings[arch] || arch; } @@ -18,7 +18,7 @@ function mapArch(arch: string): string { // return value in [darwin, linux, windows] function mapOS(os: string): string { const mappings: { [key: string]: string } = { - win32: "windows", + win32: 'windows' }; return mappings[os] || os; } @@ -27,7 +27,7 @@ async function downloadCLI(url: string): Promise { core.debug(`Downloading Terratag CLI from ${url}`); const pathToCLITar = await tc.downloadTool(url); - core.debug("Extracting Terratag CLI zip file"); + core.debug('Extracting Terratag CLI zip file'); const pathToCLI = await tc.extractTar(pathToCLITar); core.debug(`Terratag CLI path is ${pathToCLI}.`); @@ -39,42 +39,42 @@ async function downloadCLI(url: string): Promise { } async function latestVersion(): Promise { - const response = await axios.get("https://github.com/env0/terratag/releases"); + const response = await axios.get('https://github.com/env0/terratag/releases'); if (response.status !== 200) { throw new Error(`Unable to fetch terratag releases: response ${response.status}: ${response.data}`); } const regex = new RegExp('href="/env0/terratag/releases/tag/v(.{1,15})"'); const found = response.data.match(regex); if (!found) { - throw new Error("Unable to determine latest terratag version"); + throw new Error('Unable to determine latest terratag version'); } return found[1]; } function cliArgsFromActionInputs(): string[] { - const cliArgs = [`-tags=${core.getInput("tags")}`]; - const dir = core.getInput("dir"); + const cliArgs = [`-tags=${core.getInput('tags')}`]; + const dir = core.getInput('dir'); if (dir) { cliArgs.push(`-dir=${dir}`); } const boolFlag = (flagName: string) => { const value = core.getInput(flagName); if (value) { - if (value !== "true" && value !== "false") { + if (value !== 'true' && value !== 'false') { throw new Error(`${flagName} can only accept 'true' or 'false'`); } cliArgs.push(`-${flagName}=${value}`); } }; - boolFlag("skipTerratagFiles"); - boolFlag("verbose"); - boolFlag("rename"); + boolFlag('skipTerratagFiles'); + boolFlag('verbose'); + boolFlag('rename'); return cliArgs; } async function terratagVersionFromActionInputs(): Promise { - const version = core.getInput("terratagVersion"); - if (version === "latest") { + const version = core.getInput('terratagVersion'); + if (version === 'latest') { return await latestVersion(); } return version; @@ -83,8 +83,8 @@ async function terratagVersionFromActionInputs(): Promise { function terratagVersionDownloadURL(version: string): string { const osPlatform = os.platform(); const osArch = os.arch(); - if (osArch !== "x64") { - throw new Error("Terratag action currently only supports x64/amd64"); + if (osArch !== 'x64') { + throw new Error('Terratag action currently only supports x64/amd64'); } const platform = mapOS(osPlatform); @@ -107,19 +107,19 @@ export default async function run(): Promise { core.info(`Successfully installed terratag ${version}`); // Add to path core.addPath(pathToCLI); - console.info("Terratag installed, invoking"); + console.info('Terratag installed, invoking'); await new Promise((resolve, reject) => { const child = childProcess.spawn(`${pathToCLI}/terratag`, cliArgs); - child.stdout.on("data", (data) => { + child.stdout.on('data', data => { console.info(data); core.info(data); }); - child.stderr.on("data", (data) => { + child.stderr.on('data', data => { console.error(data); core.error(data); }); - child.on("close", (code) => { + child.on('close', code => { if (code === 0) { resolve(); } else { diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index dbe3b11..0000000 --- a/prettier.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - tabWidth: 2, - printWidth: 120 -}; From b38ec7f6303633e48c94d2a233656025b64b02d8 Mon Sep 17 00:00:00 2001 From: shlomp Date: Thu, 31 Dec 2020 09:48:57 +0200 Subject: [PATCH 4/7] reset all mocks by jest --- jest.config.js | 3 ++- lib/terratag-action.spec.ts | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jest.config.js b/jest.config.js index 3f1a066..10d710b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,5 +4,6 @@ module.exports = { testPathIgnorePatterns: [ "/dist/", "/node_modules/" - ] + ], + resetMocks: true, }; diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts index c781d90..8d5a53f 100644 --- a/lib/terratag-action.spec.ts +++ b/lib/terratag-action.spec.ts @@ -12,7 +12,6 @@ const mockedTC = tc as jest.Mocked; import run from './terratag-action'; test('simple end to end, latest terratag', async () => { - jest.resetAllMocks(); mockedCore.getInput.mockImplementation((name: string) => { const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; return inputs[name]; @@ -44,7 +43,6 @@ test('simple end to end, latest terratag', async () => { }); test('simple end to end, specific terratag', async () => { - jest.resetAllMocks(); mockedCore.getInput.mockImplementation((name: string) => { const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; return inputs[name]; From a9b054cb28cde162e699fc4a017a9ca4c57b13b2 Mon Sep 17 00:00:00 2001 From: shlomp Date: Thu, 31 Dec 2020 09:54:52 +0200 Subject: [PATCH 5/7] unittest: Moved common mocks to beforeAll --- lib/terratag-action.spec.ts | 99 +++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts index 8d5a53f..6aa952c 100644 --- a/lib/terratag-action.spec.ts +++ b/lib/terratag-action.spec.ts @@ -11,61 +11,54 @@ const mockedTC = tc as jest.Mocked; import run from './terratag-action'; -test('simple end to end, latest terratag', async () => { - mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; - return inputs[name]; +describe('terratag action', () => { + beforeEach(() => { + mockedTC.downloadTool.mockResolvedValue('FAKE PATH FOR DOWNLOADED TOOL TAR'); + mockedTC.extractTar.mockResolvedValue('FAKE PATH FOR EXTRACTED'); + const spawn = { + stdout: { on: jest.fn() }, + stderr: { on: jest.fn() }, + on: jest.fn() + }; + spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { + expect(eventName).toBe('close'); + callback(0); + }); + mockedChildProcess.spawn.mockReturnValue(spawn as any); }); - mockedAxios.get.mockResolvedValue({ - status: 200, - data: `href="/env0/terratag/releases/tag/v1.2.3"` + + test('simple end to end, latest terratag', async () => { + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; + return inputs[name]; + }); + mockedAxios.get.mockResolvedValue({ + status: 200, + data: `href="/env0/terratag/releases/tag/v1.2.3"` + }); + await run(); + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); + expect(mockedAxios.get.mock.calls).toEqual([['https://github.com/env0/terratag/releases']]); + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ['https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz'] + ]); + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); - mockedTC.downloadTool.mockResolvedValue('FAKE PATH FOR DOWNLOADED TOOL TAR'); - mockedTC.extractTar.mockResolvedValue('FAKE PATH FOR EXTRACTED'); - const spawn = { - stdout: { on: jest.fn() }, - stderr: { on: jest.fn() }, - on: jest.fn() - }; - spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { - expect(eventName).toBe('close'); - callback(0); - }); - mockedChildProcess.spawn.mockReturnValue(spawn as any); - await run(); - expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); - expect(mockedAxios.get.mock.calls).toEqual([['https://github.com/env0/terratag/releases']]); - expect(mockedTC.downloadTool.mock.calls).toEqual([ - ['https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz'] - ]); - expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); -}); -test('simple end to end, specific terratag', async () => { - mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; - return inputs[name]; - }); - mockedAxios.get.mockRejectedValue('Should not be called'); - mockedTC.downloadTool.mockResolvedValue('FAKE PATH FOR DOWNLOADED TOOL TAR'); - mockedTC.extractTar.mockResolvedValue('FAKE PATH FOR EXTRACTED'); - const spawn = { - stdout: { on: jest.fn() }, - stderr: { on: jest.fn() }, - on: jest.fn() - }; - spawn.on.mockImplementation((eventName: string, callback: (code: number) => void) => { - expect(eventName).toBe('close'); - callback(0); + test('simple end to end, specific terratag', async () => { + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; + return inputs[name]; + }); + mockedAxios.get.mockRejectedValue('Should not be called'); + await run(); + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); + expect(mockedAxios.get.mock.calls).toEqual([]); + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ['https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz'] + ]); + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); - mockedChildProcess.spawn.mockReturnValue(spawn as any); - await run(); - expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); - expect(mockedAxios.get.mock.calls).toEqual([]); - expect(mockedTC.downloadTool.mock.calls).toEqual([ - ['https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz'] - ]); - expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); From a0e34bd97e8ac90352b1da5184626f184e0e7bda Mon Sep 17 00:00:00 2001 From: shlomp Date: Thu, 31 Dec 2020 09:56:29 +0200 Subject: [PATCH 6/7] unit: reordered import lines to go first --- lib/terratag-action.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts index 6aa952c..23d1168 100644 --- a/lib/terratag-action.spec.ts +++ b/lib/terratag-action.spec.ts @@ -1,12 +1,12 @@ +import axios from 'axios'; +import childProcess from 'child_process'; +import core from '@actions/core'; +import tc from '@actions/tool-cache'; jest.mock('axios'); jest.mock('child_process'); -import axios from 'axios'; const mockedAxios = axios as jest.Mocked; -import childProcess from 'child_process'; const mockedChildProcess = childProcess as jest.Mocked; -import core from '@actions/core'; const mockedCore = core as jest.Mocked; -import tc from '@actions/tool-cache'; const mockedTC = tc as jest.Mocked; import run from './terratag-action'; @@ -26,7 +26,7 @@ describe('terratag action', () => { }); mockedChildProcess.spawn.mockReturnValue(spawn as any); }); - + test('simple end to end, latest terratag', async () => { mockedCore.getInput.mockImplementation((name: string) => { const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; From 43b55591179bcdbb815f62b66bbd21e202ea684f Mon Sep 17 00:00:00 2001 From: shlomp Date: Thu, 31 Dec 2020 16:26:48 +0200 Subject: [PATCH 7/7] unittest: describe hirarchy, each assertion in its own it --- lib/terratag-action.spec.ts | 80 ++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/terratag-action.spec.ts b/lib/terratag-action.spec.ts index 23d1168..dd2fea9 100644 --- a/lib/terratag-action.spec.ts +++ b/lib/terratag-action.spec.ts @@ -27,38 +27,62 @@ describe('terratag action', () => { mockedChildProcess.spawn.mockReturnValue(spawn as any); }); - test('simple end to end, latest terratag', async () => { - mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; - return inputs[name]; + describe('simple end to end, latest terratag', () => { + beforeEach(async () => { + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: 'latest', tags: JSON.stringify({ a: 'b' }) }; + return inputs[name]; + }); + mockedAxios.get.mockResolvedValue({ + status: 200, + data: `href="/env0/terratag/releases/tag/v1.2.3"` + }); + await run(); }); - mockedAxios.get.mockResolvedValue({ - status: 200, - data: `href="/env0/terratag/releases/tag/v1.2.3"` + it('shoud query which version of terratag is latest', () => { + expect(mockedAxios.get.mock.calls).toEqual([['https://github.com/env0/terratag/releases']]); + }); + it('should download terratag from expected url', () => { + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ['https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz'] + ]); + }); + it('should extract downloaded terratag', () => { + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); + }); + it('should extract downloaded terratag', () => { + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + }); + it('should execute terratag with the correct cli arguments', () => { + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); - await run(); - expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); - expect(mockedAxios.get.mock.calls).toEqual([['https://github.com/env0/terratag/releases']]); - expect(mockedTC.downloadTool.mock.calls).toEqual([ - ['https://github.com/env0/terratag/releases/download/v1.2.3/terratag_1.2.3_linux_amd64.tar.gz'] - ]); - expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); - test('simple end to end, specific terratag', async () => { - mockedCore.getInput.mockImplementation((name: string) => { - const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; - return inputs[name]; + describe('simple end to end, specific terratag', () => { + beforeEach(async () => { + mockedCore.getInput.mockImplementation((name: string) => { + const inputs: { [key: string]: string } = { terratagVersion: '5.6.7', tags: JSON.stringify({ a: 'b' }) }; + return inputs[name]; + }); + mockedAxios.get.mockRejectedValue('Should not be called'); + await run(); + }); + it('shoud NOT query which terratag versions', () => { + expect(mockedAxios.get.mock.calls).toEqual([]); + }); + it('should download terratag from expected url', () => { + expect(mockedTC.downloadTool.mock.calls).toEqual([ + ['https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz'] + ]); + }); + it('should extract downloaded terratag', () => { + expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); + }); + it('should extract downloaded terratag', () => { + expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); + }); + it('should execute terratag with the correct cli arguments', () => { + expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); - mockedAxios.get.mockRejectedValue('Should not be called'); - await run(); - expect(mockedCore.addPath.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED']]); - expect(mockedAxios.get.mock.calls).toEqual([]); - expect(mockedTC.downloadTool.mock.calls).toEqual([ - ['https://github.com/env0/terratag/releases/download/v5.6.7/terratag_5.6.7_linux_amd64.tar.gz'] - ]); - expect(mockedTC.extractTar.mock.calls).toEqual([['FAKE PATH FOR DOWNLOADED TOOL TAR']]); - expect(mockedChildProcess.spawn.mock.calls).toEqual([['FAKE PATH FOR EXTRACTED/terratag', ['-tags={"a":"b"}']]]); }); });