chore: multi-platform hooks and tests
							parent
							
								
									c1595485e8
								
							
						
					
					
						commit
						0fc027d3a1
					
				|  | @ -1,6 +1,8 @@ | ||||||
| #!/bin/sh | #!/bin/sh | ||||||
| . "$(dirname "$0")/_/husky.sh" | . "$(dirname "$0")/_/husky.sh" | ||||||
| 
 | 
 | ||||||
| yarn lint-staged --verbose | # Check changed files | ||||||
| yarn build | yarn lint-staged | ||||||
| git add dist | 
 | ||||||
|  | # Compile the action | ||||||
|  | yarn build ; git add dist | ||||||
|  |  | ||||||
|  | @ -7,11 +7,11 @@ | ||||||
|   "author": "Webber <webber@takken.io>", |   "author": "Webber <webber@takken.io>", | ||||||
|   "license": "MIT", |   "license": "MIT", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  |     "prepare": "husky install", | ||||||
|     "prebuild": "yarn", |     "prebuild": "yarn", | ||||||
|     "build": "tsc && ncc build lib --source-map --license licenses.txt", |     "build": "tsc && ncc build lib --source-map --license licenses.txt", | ||||||
|     "lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts", |     "lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts", | ||||||
|     "format": "prettier --write \"src/**/*.{js,ts}\"", |     "format": "prettier --write \"src/**/*.{js,ts}\"", | ||||||
|     "prepare": "husky install", |  | ||||||
|     "cli": "yarn ts-node src/index.ts -m cli", |     "cli": "yarn ts-node src/index.ts -m cli", | ||||||
|     "cli-aws": "cross-env cloudRunnerCluster=aws yarn run test-cli", |     "cli-aws": "cross-env cloudRunnerCluster=aws yarn run test-cli", | ||||||
|     "cli-k8s": "cross-env cloudRunnerCluster=k8s yarn run test-cli", |     "cli-k8s": "cross-env cloudRunnerCluster=k8s yarn run test-cli", | ||||||
|  | @ -66,8 +66,7 @@ | ||||||
|   "lint-staged": { |   "lint-staged": { | ||||||
|     "*.{js,jsx,ts,tsx}": [ |     "*.{js,jsx,ts,tsx}": [ | ||||||
|       "prettier --write", |       "prettier --write", | ||||||
|       "eslint", |       "eslint" | ||||||
|       "jest --findRelatedTests --passWithNoTests" |  | ||||||
|     ], |     ], | ||||||
|     "*.{json,md,yaml,yml}": [ |     "*.{json,md,yaml,yml}": [ | ||||||
|       "prettier --write" |       "prettier --write" | ||||||
|  |  | ||||||
|  | @ -1,57 +1,77 @@ | ||||||
| import * as core from '@actions/core'; | import * as core from '@actions/core'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
| import System from './system'; | import System from './system'; | ||||||
| 
 | 
 | ||||||
| jest.spyOn(core, 'debug').mockImplementation(() => {}); | jest.spyOn(core, 'debug').mockImplementation(() => {}); | ||||||
| const info = jest.spyOn(core, 'info').mockImplementation(() => {}); | const info = jest.spyOn(core, 'info').mockImplementation(() => {}); | ||||||
| jest.spyOn(core, 'warning').mockImplementation(() => {}); | jest.spyOn(core, 'warning').mockImplementation(() => {}); | ||||||
| jest.spyOn(core, 'error').mockImplementation(() => {}); | jest.spyOn(core, 'error').mockImplementation(() => {}); | ||||||
| 
 | const execSpy = jest.spyOn(exec, 'exec').mockImplementation(async () => 0); | ||||||
| afterEach(() => { |  | ||||||
|   jest.clearAllMocks(); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| describe('System', () => { | describe('System', () => { | ||||||
|   describe('run', () => { |   describe('run', () => { | ||||||
|     it('runs a command successfully', async () => { |     describe('units', () => { | ||||||
|       await expect(System.run('true')).resolves.not.toBeNull(); |       afterEach(() => jest.clearAllMocks()); | ||||||
|  | 
 | ||||||
|  |       it('passes the command to command line', async () => { | ||||||
|  |         await expect(System.run('echo test')).resolves.not.toBeNull(); | ||||||
|  |         await expect(execSpy).toHaveBeenLastCalledWith('echo test', expect.anything(), expect.anything()); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('throws on when error code is not 0', async () => { | ||||||
|  |         execSpy.mockImplementationOnce(async () => 1); | ||||||
|  |         await expect(System.run('false')).rejects.toThrowError(); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('throws when no command is given', async () => { | ||||||
|  |         await expect(System.run('')).rejects.toThrowError(); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('throws when command consists only of spaces', async () => { | ||||||
|  |         await expect(System.run(' \t\n')).rejects.toThrowError(); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('outputs info', async () => { | ||||||
|  |         execSpy.mockImplementationOnce(async (input, _, options) => { | ||||||
|  |           options?.listeners?.stdout?.(Buffer.from(input, 'utf8')); | ||||||
|  |           return 0; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         await expect(System.run('foo-bar')).resolves.not.toBeNull(); | ||||||
|  |         expect(info).toHaveBeenCalledTimes(1); | ||||||
|  |         expect(info).toHaveBeenLastCalledWith('foo-bar'); | ||||||
|  |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     it('outputs results', async () => { |     /** | ||||||
|       await expect(System.run('echo test')).resolves.toStrictEqual('test\n'); |      * Not all shells (e.g. Powershell, sh) have a reference to `echo` binary (absent or alias). | ||||||
|     }); |      * To ensure our integration with '@actions/exec' works as expected we run some specific tests in CI only | ||||||
|  |      */ | ||||||
|  |     if (process.env.CI) { | ||||||
|  |       describe('integration', () => { | ||||||
|  |         execSpy.mockRestore(); | ||||||
| 
 | 
 | ||||||
|     it('throws on when error code is not 0', async () => { |         it('runs a command successfully', async () => { | ||||||
|       await expect(System.run('false')).rejects.toThrowError(); |           await expect(System.run('true')).resolves.not.toBeNull(); | ||||||
|     }); |         }); | ||||||
| 
 | 
 | ||||||
|     it('throws when no arguments are given', async () => { |         it('outputs results', async () => { | ||||||
|       await expect(System.run('')).rejects.toThrowError(); |           await expect(System.run('echo test')).resolves.toStrictEqual('test\n'); | ||||||
|     }); |         }); | ||||||
| 
 | 
 | ||||||
|     it('outputs info', async () => { |         it('throws on when error code is not 0', async () => { | ||||||
|       await expect(System.run('echo test')).resolves.not.toBeNull(); |           await expect(System.run('false')).rejects.toThrowError(); | ||||||
|       expect(info).toHaveBeenLastCalledWith('test\n'); |         }); | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     it('outputs info only once', async () => { |         it('allows pipes using buffer', async () => { | ||||||
|       await expect(System.run('echo 1')).resolves.not.toBeNull(); |           await expect( | ||||||
|       expect(info).toHaveBeenCalledTimes(1); |             System.run('sh', undefined, { | ||||||
|       expect(info).toHaveBeenLastCalledWith('1\n'); |               input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'), | ||||||
| 
 |               // eslint-disable-next-line github/no-then
 | ||||||
|       info.mockClear(); |             }).then((result) => Number(result)), | ||||||
|       await expect(System.run('echo 2')).resolves.not.toBeNull(); |           ).resolves.not.toBeNaN(); | ||||||
|       await expect(System.run('echo 3')).resolves.not.toBeNull(); |         }); | ||||||
|       expect(info).toHaveBeenCalledTimes(2); |       }); | ||||||
|       expect(info).toHaveBeenLastCalledWith('3\n'); |     } | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     it('allows pipes using buffer', async () => { |  | ||||||
|       await expect( |  | ||||||
|         System.run('sh', undefined, { |  | ||||||
|           input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'), |  | ||||||
|           // eslint-disable-next-line github/no-then
 |  | ||||||
|         }).then((result) => Number(result)), |  | ||||||
|       ).resolves.not.toBeNaN(); |  | ||||||
|     }); |  | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -45,6 +45,10 @@ class System { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|  |       if (command.trim() === '') { | ||||||
|  |         throw new Error(`Failed to execute empty command`); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       const exitCode = await exec(command, arguments_, { silent: true, listeners, ...options }); |       const exitCode = await exec(command, arguments_, { silent: true, listeners, ...options }); | ||||||
|       showOutput(); |       showOutput(); | ||||||
|       if (exitCode !== 0) { |       if (exitCode !== 0) { | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										12
									
								
								yarn.lock
								
								
								
								
							|  | @ -3941,9 +3941,9 @@ lines-and-columns@^1.1.6: | ||||||
|   integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= |   integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= | ||||||
| 
 | 
 | ||||||
| lint-staged@^12.3.4: | lint-staged@^12.3.4: | ||||||
|   version "12.3.4" |   version "12.3.7" | ||||||
|   resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.4.tgz#4b1ff8c394c3e6da436aaec5afd4db18b5dac360" |   resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.7.tgz#ad0e2014302f704f9cf2c0ebdb97ac63d0f17be0" | ||||||
|   integrity sha512-yv/iK4WwZ7/v0GtVkNb3R82pdL9M+ScpIbJLJNyCXkJ1FGaXvRCOg/SeL59SZtPpqZhE7BD6kPKFLIDUhDx2/w== |   integrity sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ== | ||||||
|   dependencies: |   dependencies: | ||||||
|     cli-truncate "^3.1.0" |     cli-truncate "^3.1.0" | ||||||
|     colorette "^2.0.16" |     colorette "^2.0.16" | ||||||
|  | @ -3955,6 +3955,7 @@ lint-staged@^12.3.4: | ||||||
|     micromatch "^4.0.4" |     micromatch "^4.0.4" | ||||||
|     normalize-path "^3.0.0" |     normalize-path "^3.0.0" | ||||||
|     object-inspect "^1.12.0" |     object-inspect "^1.12.0" | ||||||
|  |     pidtree "^0.5.0" | ||||||
|     string-argv "^0.3.1" |     string-argv "^0.3.1" | ||||||
|     supports-color "^9.2.1" |     supports-color "^9.2.1" | ||||||
|     yaml "^1.10.2" |     yaml "^1.10.2" | ||||||
|  | @ -4498,6 +4499,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: | ||||||
|   resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz" |   resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz" | ||||||
|   integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== |   integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== | ||||||
| 
 | 
 | ||||||
|  | pidtree@^0.5.0: | ||||||
|  |   version "0.5.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.5.0.tgz#ad5fbc1de78b8a5f99d6fbdd4f6e4eee21d1aca1" | ||||||
|  |   integrity sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA== | ||||||
|  | 
 | ||||||
| pify@^2.0.0: | pify@^2.0.0: | ||||||
|   version "2.3.0" |   version "2.3.0" | ||||||
|   resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" |   resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue