From b7e8a5bdba6e295171fdaa5a351cbb391f345554 Mon Sep 17 00:00:00 2001 From: Michael T Lombardi Date: Thu, 13 Oct 2022 23:13:33 -0500 Subject: [PATCH] (GH-608) Add getConventions and refactor This commit introduces the getConventions function, which does a one-time calculation for the changes in packaging conventions to propagate to the getArch and getOS functions. It updates those functions and the installer code to leverage the conventions. Finally, it updates the test arrangement for getArch and getOS to use test cases instead of repeating the same test over and over and adds unit tests for the new getConventions function. --- __tests__/get-arch.test.ts | 172 ++++++++++++++++++++---------- __tests__/get-conventions.test.ts | 57 ++++++++++ __tests__/get-os.test.ts | 101 +++++++++++++++--- src/get-arch.ts | 27 ++--- src/get-conventions.ts | 29 +++++ src/get-os.ts | 12 ++- src/installer.ts | 7 +- 7 files changed, 306 insertions(+), 99 deletions(-) create mode 100644 __tests__/get-conventions.test.ts create mode 100644 src/get-conventions.ts diff --git a/__tests__/get-arch.test.ts b/__tests__/get-arch.test.ts index d59cc45..8e00ee2 100644 --- a/__tests__/get-arch.test.ts +++ b/__tests__/get-arch.test.ts @@ -1,63 +1,121 @@ import getArch from '../src/get-arch'; describe('getArch', () => { - test('processor architecture < 0.102.0', () => { - expect(getArch('x64', 'linux', '0.101.0')).toBe('64bit'); - expect(getArch('x64', 'macOS', '0.101.0')).toBe('64bit'); - expect(getArch('x64', 'windows', '0.101.0')).toBe('64bit'); - - expect(getArch('arm', 'linux', '0.101.0')).toBe('ARM'); - expect(getArch('arm', 'macOS', '0.101.0')).toBe('ARM'); - expect(getArch('arm', 'windows', '0.101.0')).toBe('ARM'); - - expect(getArch('arm64', 'linux', '0.101.0')).toBe('ARM64'); - expect(getArch('arm64', 'macOS', '0.101.0')).toBe('ARM64'); - expect(getArch('arm64', 'windows', '0.101.0')).toBe('ARM64'); + const groups = [ + { + condition: 'when hugo version < 0.102.0', + conventions: { + arch: { + darwinUniversal: false, + dropped32BitSupport: false, + standardizedNaming: false, + }, + os: { + renamedMacOS: false, + downcasedAll: false + } + }, + tests: [ + { arch: 'x64', os: 'linux', expected: '64bit' }, + { arch: 'x64', os: 'macOS', expected: '64bit' }, + { arch: 'x64', os: 'windows', expected: '64bit' }, + { arch: 'arm', os: 'linux', expected: 'ARM' }, + { arch: 'arm', os: 'macOS', expected: 'ARM' }, + { arch: 'arm', os: 'windows', expected: 'ARM' }, + { arch: 'arm64', os: 'linux', expected: 'ARM64' }, + { arch: 'arm64', os: 'macOS', expected: 'ARM64' }, + { arch: 'arm64', os: 'windows', expected: 'ARM64' }, + ] + }, + { + condition: 'when hugo version === 0.102.z', + conventions: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: false, + }, + os: { + renamedMacOS: true, + downcasedAll: false + } + }, + tests: [ + { arch: 'x64', os: 'linux', expected: '64bit' }, + { arch: 'x64', os: 'macOS', expected: 'universal' }, + { arch: 'x64', os: 'windows', expected: '64bit' }, + { arch: 'arm', os: 'linux', throws: true }, + { arch: 'arm', os: 'macOS', expected: 'universal' }, + { arch: 'arm', os: 'windows', throws: true }, + { arch: 'arm64', os: 'linux', expected: 'ARM64' }, + { arch: 'arm64', os: 'macOS', expected: 'universal' }, + { arch: 'arm64', os: 'windows', expected: 'ARM64' }, + ] + }, + { + condition: 'when hugo version >= 0.103.0', + conventions: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: true, + }, + os: { + renamedMacOS: true, + downcasedAll: true + } + }, + tests: [ + { arch: 'x64', os: 'linux', expected: 'amd64' }, + { arch: 'x64', os: 'macOS', expected: 'universal' }, + { arch: 'x64', os: 'windows', expected: 'amd64' }, + { arch: 'arm', os: 'linux', throws: true }, + { arch: 'arm', os: 'macOS', expected: 'universal' }, + { arch: 'arm', os: 'windows', throws: true }, + { arch: 'arm64', os: 'linux', expected: 'arm64' }, + { arch: 'arm64', os: 'macOS', expected: 'universal' }, + { arch: 'arm64', os: 'windows', expected: 'arm64' }, + ] + }, + { + condition: 'when the architecture is unsupported for the action', + conventions: { + arch: { + darwinUniversal: false, + dropped32BitSupport: false, + standardizedNaming: false, + }, + os: { + renamedMacOS: false, + downcasedAll: false + } + }, + tests: [ + { arch: 'mips', os: 'linux', throws: true} + ] + } + ].map(function (group) { + group.tests = group.tests.map(function (example) { + return Object.assign(example, { + toString: function () { + let name = `${example.os} on ${example.arch} ` + name += example?.throws ? 'throws as not supported' : `returns ${example.expected}` + return name; + } + }); + }) + return Object.assign(group, { toString: function () { return group.condition } }); }); - test('processor architecture === 0.102.z', () => { - expect(getArch('x64', 'linux', '0.102.0')).toBe('64bit'); - expect(getArch('x64', 'macOS', '0.102.0')).toBe('universal'); - expect(getArch('x64', 'windows', '0.102.0')).toBe('64bit'); - - expect(getArch('arm', 'macOS', '0.102.0')).toBe('universal'); - - expect(getArch('arm64', 'linux', '0.102.0')).toBe('ARM64'); - expect(getArch('arm64', 'macOS', '0.102.0')).toBe('universal'); - expect(getArch('arm64', 'windows', '0.102.0')).toBe('ARM64'); - }); - - test('processor architecture === 0.103.z', () => { - expect(getArch('x64', 'linux', '0.103.0')).toBe('amd64'); - expect(getArch('x64', 'darwin', '0.103.0')).toBe('universal'); - expect(getArch('x64', 'windows', '0.103.0')).toBe('amd64'); - - expect(getArch('arm', 'darwin', '0.103.0')).toBe('universal'); - - expect(getArch('arm64', 'linux', '0.103.0')).toBe('arm64'); - expect(getArch('arm64', 'darwin', '0.103.0')).toBe('universal'); - expect(getArch('arm64', 'windows', '0.103.0')).toBe('arm64'); - }); - - test('processor architecture > 0.103.0', () => { - expect(getArch('x64', 'linux', '0.104.0')).toBe('amd64'); - expect(getArch('x64', 'darwin', '0.104.0')).toBe('universal'); - expect(getArch('x64', 'windows', '0.104.0')).toBe('amd64'); - - expect(getArch('arm', 'darwin', '0.104.0')).toBe('universal'); - - expect(getArch('arm64', 'linux', '0.104.0')).toBe('arm64'); - expect(getArch('arm64', 'darwin', '0.104.0')).toBe('universal'); - expect(getArch('arm64', 'windows', '0.104.0')).toBe('arm64'); - }); - - test('exception', () => { - expect(() => { - getArch('mips', 'linux', '0.101.0'); - }).toThrow('mips is not supported'); - - expect(() => { - getArch('arm', 'linux', '0.102.0') - }).toThrow('arm is not supported'); - }); + describe.each(groups)('%s', ({ conventions, tests }) => { + test.each(tests)('%s', ({ arch, os, throws, expected }) => { + if (throws) { + expect(() => { + getArch(arch, os, conventions) + }).toThrow(`${arch} is not supported`); + } else { + expect(getArch(arch, os, conventions)).toBe(expected); + } + }) + }) }); diff --git a/__tests__/get-conventions.test.ts b/__tests__/get-conventions.test.ts new file mode 100644 index 0000000..f264551 --- /dev/null +++ b/__tests__/get-conventions.test.ts @@ -0,0 +1,57 @@ +import getConventions from "../src/get-conventions"; + +describe('getConventions()', () => { + const groups = [ + { + condition: 'when hugo version < 0.102.0', + version: '0.101.0', + expected: { + arch: { + darwinUniversal: false, + dropped32BitSupport: false, + standardizedNaming: false, + }, + os: { + renamedMacOS: false, + downcasedAll: false + } + } + }, + { + condition: 'when hugo version === 0.102.z', + version: '0.102.0', + expected: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: false, + }, + os: { + renamedMacOS: true, + downcasedAll: false + } + } + }, + { + condition: 'when hugo version >= 0.103.0', + version: '0.103.0', + expected: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: true, + }, + os: { + renamedMacOS: true, + downcasedAll: true + } + } + } + ].map(function (group) { + return Object.assign(group, { toString: function () { return group.condition } }); + }); + + test.each(groups)('%s', ({ expected, version }) => { + expect(getConventions(version)).toEqual(expected); + }); +}); diff --git a/__tests__/get-os.test.ts b/__tests__/get-os.test.ts index 0e67078..7953c00 100644 --- a/__tests__/get-os.test.ts +++ b/__tests__/get-os.test.ts @@ -1,27 +1,96 @@ import getOS from '../src/get-os'; describe('getOS', () => { - test('os type', () => { - expect(getOS('linux', '0.101.0')).toBe('Linux'); - expect(getOS('darwin', '0.101.0')).toBe('macOS'); - expect(getOS('win32', '0.101.0')).toBe('Windows'); + const groups = [ + { + condition: 'when hugo version < 0.102.0', + conventions: { + arch: { + darwinUniversal: false, + dropped32BitSupport: false, + standardizedNaming: false, + }, + os: { + renamedMacOS: false, + downcasedAll: false + } + }, + tests: [ + { os: 'linux', expected: 'Linux' }, + { os: 'darwin', expected: 'macOS' }, + { os: 'win32', expected: 'Windows' }, + ], + }, + { + condition: 'when hugo version === 0.102.z', + conventions: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: false, + }, + os: { + renamedMacOS: true, + downcasedAll: false + } + }, + tests: [ + { os: 'linux', expected: 'Linux' }, + { os: 'darwin', expected: 'darwin' }, + { os: 'win32', expected: 'Windows' }, + ], + }, + { + condition: 'when hugo version >= 0.103.0', + conventions: { + arch: { + darwinUniversal: true, + dropped32BitSupport: true, + standardizedNaming: true, + }, + os: { + renamedMacOS: true, + downcasedAll: true + } + }, + tests: [ + { os: 'linux', expected: 'linux' }, + { os: 'darwin', expected: 'darwin' }, + { os: 'win32', expected: 'windows' }, + ], + } + ].map(function (group) { + group.tests = group.tests.map(function (example) { + return Object.assign(example, { + toString: function () { + return `${example.os} returns ${example.expected}` + } + }); + }) + return Object.assign(group, { toString: function () { return group.condition } }); + }); - expect(getOS('linux', '0.102.0')).toBe('Linux'); - expect(getOS('darwin', '0.102.0')).toBe('darwin'); - expect(getOS('win32', '0.102.0')).toBe('Windows'); - - expect(getOS('linux', '0.103.0')).toBe('linux'); - expect(getOS('darwin', '0.103.0')).toBe('darwin'); - expect(getOS('win32', '0.103.0')).toBe('windows'); - - expect(getOS('linux', '0.104.0')).toBe('linux'); - expect(getOS('darwin', '0.104.0')).toBe('darwin'); - expect(getOS('win32', '0.104.0')).toBe('windows'); + describe.each(groups)('%s', ({ conventions, tests }) => { + test.each(tests)('%s', ({ os, expected }) => { + expect(getOS(os, conventions)).toBe(expected); + }) }); test('exception', () => { + const conventions = { + arch: { + darwinUniversal: false, + dropped32BitSupport: false, + standardizedNaming: false, + }, + os: { + renamedMacOS: false, + downcasedAll: false + } + } + expect(() => { - getOS('centos', '0.101.0'); + getOS('centos', conventions); }).toThrow('centos is not supported'); }); }); diff --git a/src/get-arch.ts b/src/get-arch.ts index 1ab05b8..566f59f 100644 --- a/src/get-arch.ts +++ b/src/get-arch.ts @@ -1,32 +1,21 @@ -export default function getArch(arch: string, os: string, version: string): string { - const segments = version.split('.').map(s => parseInt(s)); +import { conventions } from "./get-conventions"; - if (os == 'darwin' || (os == 'macOS' && segments[0] >= 0 && segments[1] >= 102)) { +export default function getArch(arch: string, os: string, conventions: conventions): string { + if (os == 'darwin' || os == 'macOS' && conventions.arch.darwinUniversal) { return 'universal' } - if (segments[0] >= 0 && segments[1] >= 103) { - switch (arch) { - case 'x64': - return 'amd64'; - case 'arm64': - return 'arm64'; - default: - throw new Error(`${arch} is not supported`); - } - } - switch (arch) { case 'x64': - return (segments[0] >= 0 && segments[1] >= 103) ? 'amd64' : '64bit'; + return conventions.arch.standardizedNaming ? 'amd64': '64bit' ; case 'arm': - if (segments[0] >= 0 && segments[1] < 102) { - return 'ARM'; - } else { + if (conventions.arch.dropped32BitSupport) { throw new Error(`${arch} is not supported`); } + + return 'ARM'; case 'arm64': - return (segments[0] >= 0 && segments[1] >= 103) ? 'arm64' : 'ARM64'; + return conventions.arch.standardizedNaming ? 'arm64' : 'ARM64'; default: throw new Error(`${arch} is not supported`); } diff --git a/src/get-conventions.ts b/src/get-conventions.ts new file mode 100644 index 0000000..277346f --- /dev/null +++ b/src/get-conventions.ts @@ -0,0 +1,29 @@ +export interface conventions { + arch: { + darwinUniversal: boolean, + dropped32BitSupport: boolean, + standardizedNaming: boolean + }, + os: { + renamedMacOS: boolean, + downcasedAll: boolean + } +} + +export default function getConventions(version: string,): conventions { + const segments = version.split('.').map(s => parseInt(s)); + const stableOrNewer = segments[0] > 0; + const newerThan103 = stableOrNewer || segments[1] >= 103 + const newerThan102 = stableOrNewer || segments[1] >= 102 + return { + arch: { + darwinUniversal: newerThan102, + dropped32BitSupport: newerThan102, + standardizedNaming: newerThan103 + }, + os: { + renamedMacOS: newerThan102, + downcasedAll: newerThan103 + } + } +} diff --git a/src/get-os.ts b/src/get-os.ts index 0e97e97..f48c8bb 100644 --- a/src/get-os.ts +++ b/src/get-os.ts @@ -1,12 +1,14 @@ -export default function getOS(platform: string, version: string): string { - const segments = version.split('.').map(s => parseInt(s)); +import { conventions } from "./get-conventions"; + +export default function getOS(platform: string, conventions: conventions): string { + switch (platform) { case 'linux': - return (segments[0] >= 0 && segments[1] >= 103) ? 'linux' : 'Linux' + return conventions.os.downcasedAll ? 'linux' : 'Linux' case 'darwin': - return (segments[0] >= 0 && segments[1] >= 102) ? 'darwin' : 'macOS' + return conventions.os.renamedMacOS ? 'darwin' : 'macOS' case 'win32': - return (segments[0] >= 0 && segments[1] >= 103) ? 'windows' : 'Windows' + return conventions.os.downcasedAll ? 'windows' : 'Windows' default: throw new Error(`${platform} is not supported`); } diff --git a/src/installer.ts b/src/installer.ts index 9d188fb..76b408d 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as tc from '@actions/tool-cache'; import * as io from '@actions/io'; +import getConventions from './get-conventions'; import getOS from './get-os'; import getArch from './get-arch'; import getURL from './get-url'; @@ -47,10 +48,12 @@ export async function installer(version: string): Promise { const extended: string = core.getInput('extended'); core.debug(`Hugo extended: ${extended}`); - const osName: string = getOS(process.platform, version); + const conventions = getConventions(version); + + const osName: string = getOS(process.platform, conventions); core.debug(`Operating System: ${osName}`); - const archName: string = getArch(process.arch, osName, version); + const archName: string = getArch(process.arch, osName, conventions); core.debug(`Processor Architecture: ${archName}`); const toolURL: string = getURL(osName, archName, extended, version);