diff --git a/src/run.test.ts b/src/run.test.ts index fc324abe..8b022108 100644 --- a/src/run.test.ts +++ b/src/run.test.ts @@ -6,84 +6,74 @@ import * as path from 'path' import * as core from '@actions/core' describe('run.ts', () => { + const downloadBaseURL = 'https://test.tld' + + // Cleanup mocks after each test to ensure that subsequent tests are not affected by the mocks. + afterEach(() => { + jest.restoreAllMocks() + }) + test('getExecutableExtension() - return .exe when os is Windows', () => { - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') + jest.spyOn(os, 'platform').mockReturnValue('win32') expect(run.getExecutableExtension()).toBe('.exe') - expect(os.type).toHaveBeenCalled() + expect(os.platform).toHaveBeenCalled() }) test('getExecutableExtension() - return empty string for non-windows OS', () => { - jest.spyOn(os, 'type').mockReturnValue('Darwin') + jest.spyOn(os, 'platform').mockReturnValue('darwin') expect(run.getExecutableExtension()).toBe('') - expect(os.type).toHaveBeenCalled() + expect(os.platform).toHaveBeenCalled() }) - test('getHelmDownloadURL() - return the URL to download helm for Linux', () => { - const downloadBaseURL = 'https://test.tld' + test('getHelmDownloadURL() - return the URL to download helm for Linux amd64', () => { + jest.spyOn(os, 'platform').mockReturnValue('linux') + jest.spyOn(os, 'arch').mockReturnValue('x64') + const expected = 'https://test.tld/helm-v3.8.0-linux-amd64.tar.gz' - jest.spyOn(os, 'type').mockReturnValue('Linux') - jest.spyOn(os, 'arch').mockReturnValueOnce('unknown') - const helmLinuxUrl = 'https://test.tld/helm-v3.8.0-linux-amd64.zip' - - expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe( - helmLinuxUrl - ) - expect(os.type).toHaveBeenCalled() + expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe(expected) + expect(os.platform).toHaveBeenCalled() expect(os.arch).toHaveBeenCalled() + }) - // arm64 - jest.spyOn(os, 'type').mockReturnValue('Linux') - jest.spyOn(os, 'arch').mockReturnValueOnce('arm64') - const helmLinuxArm64Url = 'https://test.tld/helm-v3.8.0-linux-arm64.zip' + test('getHelmDownloadURL() - return the URL to download helm for Linux arm64', () => { + jest.spyOn(os, 'platform').mockReturnValue('linux') + jest.spyOn(os, 'arch').mockReturnValue('arm64') + const expected = 'https://test.tld/helm-v3.8.0-linux-arm64.tar.gz' - expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe( - helmLinuxArm64Url - ) - expect(os.type).toHaveBeenCalled() + expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe(expected) + expect(os.platform).toHaveBeenCalled() expect(os.arch).toHaveBeenCalled() }) - test('getHelmDownloadURL() - return the URL to download helm for Darwin', () => { - const downloadBaseURL = 'https://test.tld' - - jest.spyOn(os, 'type').mockReturnValue('Darwin') - jest.spyOn(os, 'arch').mockReturnValueOnce('unknown') - const helmDarwinUrl = 'https://test.tld/helm-v3.8.0-darwin-amd64.zip' + test('getHelmDownloadURL() - return the URL to download helm for Darwin x64', () => { + jest.spyOn(os, 'platform').mockReturnValue('darwin') + jest.spyOn(os, 'arch').mockReturnValue('x64') + const expected = 'https://test.tld/helm-v3.8.0-darwin-amd64.tar.gz' - expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe( - helmDarwinUrl - ) - expect(os.type).toHaveBeenCalled() + expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe(expected) + expect(os.platform).toHaveBeenCalled() expect(os.arch).toHaveBeenCalled() + }) - // arm64 - jest.spyOn(os, 'type').mockReturnValue('Darwin') - jest.spyOn(os, 'arch').mockReturnValueOnce('arm64') - const helmDarwinArm64Url = 'https://test.tld/helm-v3.8.0-darwin-arm64.zip' + test('getHelmDownloadURL() - return the URL to download helm for Darwin arm64', () => { + jest.spyOn(os, 'platform').mockReturnValue('darwin') + jest.spyOn(os, 'arch').mockReturnValue('arm64') + const expected = 'https://test.tld/helm-v3.8.0-darwin-arm64.tar.gz' - expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe( - helmDarwinArm64Url - ) - expect(os.type).toHaveBeenCalled() + expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe(expected) + expect(os.platform).toHaveBeenCalled() expect(os.arch).toHaveBeenCalled() }) - test('getValidVersion() - return version with v prepended', () => { - expect(run.getValidVersion('3.8.0')).toBe('v3.8.0') - }) - test('getHelmDownloadURL() - return the URL to download helm for Windows', () => { - const downloadBaseURL = 'https://test.tld' - - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') + jest.spyOn(os, 'platform').mockReturnValue('win32') + jest.spyOn(os, 'arch').mockReturnValue('x64') - const helmWindowsUrl = 'https://test.tld/helm-v3.8.0-windows-amd64.zip' - expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe( - helmWindowsUrl - ) - expect(os.type).toHaveBeenCalled() + const expected = 'https://test.tld/helm-v3.8.0-windows-amd64.zip' + expect(run.getHelmDownloadURL(downloadBaseURL, 'v3.8.0')).toBe(expected) + expect(os.platform).toHaveBeenCalled() }) test('getLatestHelmVersion() - return the latest version of HELM', async () => { @@ -101,6 +91,10 @@ describe('run.ts', () => { expect(await run.getLatestHelmVersion()).toBe('v3.13.3') }) + test('getValidVersion() - return version with v prepended', () => { + expect(run.getValidVersion('3.8.0')).toBe('v3.8.0') + }) + test('walkSync() - return path to the all files matching fileToFind in dir', () => { jest.spyOn(fs, 'readdirSync').mockImplementation((file, _) => { if (file == 'mainFolder') @@ -120,6 +114,7 @@ describe('run.ts', () => { 'file21' as unknown as fs.Dirent, 'file22' as unknown as fs.Dirent ] + return [] }) jest.spyOn(core, 'debug').mockImplementation() jest.spyOn(fs, 'statSync').mockImplementation((file) => { @@ -154,6 +149,7 @@ describe('run.ts', () => { 'file21' as unknown as fs.Dirent, 'file22' as unknown as fs.Dirent ] + return [] }) jest.spyOn(core, 'debug').mockImplementation() jest.spyOn(fs, 'statSync').mockImplementation((file) => { @@ -171,13 +167,14 @@ describe('run.ts', () => { jest.spyOn(fs, 'chmodSync').mockImplementation(() => {}) jest.spyOn(fs, 'readdirSync').mockImplementation((file, _) => { if (file == 'mainFolder') return ['helm.exe' as unknown as fs.Dirent] + return [] }) jest.spyOn(fs, 'statSync').mockImplementation((file) => { const isDirectory = (file as string).indexOf('folder') == -1 ? false : true return {isDirectory: () => isDirectory} as fs.Stats }) - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') + jest.spyOn(os, 'platform').mockReturnValue('win32') expect(run.findHelm('mainFolder')).toBe( path.join('mainFolder', 'helm.exe') @@ -188,11 +185,13 @@ describe('run.ts', () => { jest.spyOn(fs, 'chmodSync').mockImplementation(() => {}) jest.spyOn(fs, 'readdirSync').mockImplementation((file, _) => { if (file == 'mainFolder') return [] + return [] }) jest.spyOn(fs, 'statSync').mockImplementation((file) => { return {isDirectory: () => true} as fs.Stats }) - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') + jest.spyOn(os, 'platform').mockReturnValue('win32') + expect(() => run.findHelm('mainFolder')).toThrow( 'Helm executable not found in path mainFolder' ) @@ -203,11 +202,9 @@ describe('run.ts', () => { jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool') const response = JSON.stringify([{tag_name: 'v4.0.0'}]) jest.spyOn(fs, 'readFileSync').mockReturnValue(response) - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') + jest.spyOn(os, 'platform').mockReturnValue('win32') jest.spyOn(fs, 'chmodSync').mockImplementation(() => {}) - jest - .spyOn(toolCache, 'extractZip') - .mockResolvedValue('pathToUnzippedHelm') + jest.spyOn(toolCache, 'extractZip').mockResolvedValue('extractedPath') jest.spyOn(toolCache, 'cacheDir').mockResolvedValue('pathToCachedDir') jest .spyOn(fs, 'readdirSync') @@ -218,9 +215,7 @@ describe('run.ts', () => { return {isDirectory: () => isDirectory} as fs.Stats }) - const baseURL = 'https://test.tld' - - expect(await run.downloadHelm(baseURL, 'v4.0.0')).toBe( + expect(await run.downloadHelm(downloadBaseURL, 'v4.0.0')).toBe( path.join('pathToCachedDir', 'helm.exe') ) expect(toolCache.find).toHaveBeenCalledWith('helm', 'v4.0.0') @@ -240,26 +235,33 @@ describe('run.ts', () => { jest.spyOn(toolCache, 'downloadTool').mockImplementation(async () => { throw 'Unable to download' }) - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') - - const baseURL = 'https://test.tld' + jest.spyOn(os, 'platform').mockReturnValue('win32') - await expect(run.downloadHelm(baseURL, 'v3.2.1')).rejects.toThrow( - 'Failed to download Helm from location https://test.tld/helm-v3.2.1-windows-amd64.zip' + const downloadUrl = 'https://test.tld/helm-v3.2.1-windows-amd64.zip' + await expect(run.downloadHelm(downloadBaseURL, 'v3.2.1')).rejects.toThrow( + `Failed to download Helm from location ${downloadUrl}` ) expect(toolCache.find).toHaveBeenCalledWith('helm', 'v3.2.1') - expect(toolCache.downloadTool).toHaveBeenCalledWith( - 'https://test.tld/helm-v3.2.1-windows-amd64.zip' - ) + expect(toolCache.downloadTool).toHaveBeenCalledWith(`${downloadUrl}`) }) test('downloadHelm() - return path to helm tool with same version from toolCache', async () => { jest.spyOn(toolCache, 'find').mockReturnValue('pathToCachedDir') + jest.spyOn(toolCache, 'cacheDir').mockResolvedValue('pathToCachedDir') + jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool') + jest.spyOn(toolCache, 'extractZip').mockResolvedValue('extractedPath') + jest.spyOn(os, 'platform').mockReturnValue('win32') jest.spyOn(fs, 'chmodSync').mockImplementation(() => {}) + jest + .spyOn(fs, 'readdirSync') + .mockReturnValue(['helm.exe' as unknown as fs.Dirent]) + jest.spyOn(fs, 'statSync').mockImplementation((file) => { + const isDirectory = + (file as string).indexOf('folder') == -1 ? false : true + return {isDirectory: () => isDirectory} as fs.Stats + }) - const baseURL = 'https://test.tld' - - expect(await run.downloadHelm(baseURL, 'v3.2.1')).toBe( + expect(await run.downloadHelm(downloadBaseURL, 'v3.2.1')).toBe( path.join('pathToCachedDir', 'helm.exe') ) expect(toolCache.find).toHaveBeenCalledWith('helm', 'v3.2.1') @@ -272,12 +274,11 @@ describe('run.ts', () => { test('downloadHelm() - throw error is helm is not found in path', async () => { jest.spyOn(toolCache, 'find').mockReturnValue('') jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool') - jest.spyOn(os, 'type').mockReturnValue('Windows_NT') - jest.spyOn(fs, 'chmodSync').mockImplementation() - jest - .spyOn(toolCache, 'extractZip') - .mockResolvedValue('pathToUnzippedHelm') jest.spyOn(toolCache, 'cacheDir').mockResolvedValue('pathToCachedDir') + jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool') + jest.spyOn(toolCache, 'extractZip').mockResolvedValue('extractedPath') + jest.spyOn(os, 'platform').mockReturnValue('win32') + jest.spyOn(fs, 'chmodSync').mockImplementation() jest.spyOn(fs, 'readdirSync').mockImplementation((file, _) => []) jest.spyOn(fs, 'statSync').mockImplementation((file) => { const isDirectory = @@ -285,9 +286,7 @@ describe('run.ts', () => { return {isDirectory: () => isDirectory} as fs.Stats }) - const baseURL = 'https://test.tld' - - await expect(run.downloadHelm(baseURL, 'v3.2.1')).rejects.toThrow( + await expect(run.downloadHelm(downloadBaseURL, 'v3.2.1')).rejects.toThrow( 'Helm executable not found in path pathToCachedDir' ) expect(toolCache.find).toHaveBeenCalledWith('helm', 'v3.2.1') diff --git a/src/run.ts b/src/run.ts index aaab9ecf..dbef9f9a 100644 --- a/src/run.ts +++ b/src/run.ts @@ -61,41 +61,24 @@ export async function getLatestHelmVersion(): Promise { } } +export function getArch(): string { + return os.arch() === 'x64' ? 'amd64' : os.arch() +} + +export function getPlatform(): string { + return os.platform() === 'win32' ? 'windows' : os.platform() +} + +export function getArchiveExtension(): string { + return os.platform() === 'win32' ? 'zip' : 'tar.gz' +} + export function getExecutableExtension(): string { - if (os.type().match(/^Win/)) { - return '.exe' - } - return '' + return os.platform() === 'win32' ? '.exe' : '' } -const LINUX = 'Linux' -const MAC_OS = 'Darwin' -const WINDOWS = 'Windows_NT' -const ARM64 = 'arm64' export function getHelmDownloadURL(baseURL: string, version: string): string { - const arch = os.arch() - const operatingSystem = os.type() - - let urlPath = '' - - switch (true) { - case operatingSystem == LINUX && arch == ARM64: - urlPath = util.format(`/helm-%s-linux-arm64.zip`, version) - break - case operatingSystem == LINUX: - urlPath = util.format(`/helm-%s-linux-amd64.zip`, version) - break - case operatingSystem == MAC_OS && arch == ARM64: - urlPath = util.format(`/helm-%s-darwin-arm64.zip`, version) - break - case operatingSystem == MAC_OS: - urlPath = util.format(`/helm-%s-darwin-amd64.zip`, version) - break - case operatingSystem == WINDOWS: - default: - urlPath = util.format(`/helm-%s-windows-amd64.zip`, version) - } - + const urlPath = `helm-${version}-${getPlatform()}-${getArch()}.${getArchiveExtension()}` const url = new URL(urlPath, baseURL) return url.toString() } @@ -121,9 +104,13 @@ export async function downloadHelm( } fs.chmodSync(helmDownloadPath, '777') - const unzipedHelmPath = await toolCache.extractZip(helmDownloadPath) + const extractedPath = + getPlatform() === 'windows' + ? await toolCache.extractZip(helmDownloadPath) + : await toolCache.extractTar(helmDownloadPath) + cachedToolpath = await toolCache.cacheDir( - unzipedHelmPath, + extractedPath, helmToolName, version )