From 2c62681dc97398844ab86571ae9414d21c6be68d Mon Sep 17 00:00:00 2001 From: panticmilos Date: Mon, 8 Aug 2022 11:05:52 +0200 Subject: [PATCH] Add support for arm32 go arch --- __tests__/setup-go.test.ts | 54 ++++++++++++++++++++++++++++++++------ action.yml | 2 ++ dist/setup/index.js | 43 +++++++++++++++++------------- src/installer.ts | 52 +++++++++++++++++++++++------------- 4 files changed, 107 insertions(+), 44 deletions(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 9e39075..05f4eb5 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -7,6 +7,7 @@ import osm from 'os'; import path from 'path'; import * as main from '../src/main'; import * as im from '../src/installer'; +import * as sys from '../src/system'; let goJsonData = require('./data/golang-dl.json'); let matchers = require('../matchers.json'); @@ -41,6 +42,7 @@ describe('setup-go', () => { let mkdirpSpy: jest.SpyInstance; let execSpy: jest.SpyInstance; let getManifestSpy: jest.SpyInstance; + let sysGetArchSpy: jest.SpyInstance; beforeAll(async () => { process.env['GITHUB_ENV'] = ''; // Stub out Environment file functionality so we can verify it writes to standard out (toolkit is backwards compatible) @@ -64,6 +66,7 @@ describe('setup-go', () => { archSpy = jest.spyOn(osm, 'arch'); archSpy.mockImplementation(() => os['arch']); execSpy = jest.spyOn(cp, 'execSync'); + sysGetArchSpy = jest.spyOn(sys, 'getArch'); // switch path join behaviour based on set os.platform joinSpy = jest.spyOn(path, 'join'); @@ -129,7 +132,7 @@ describe('setup-go', () => { it('can find 1.9.7 from manifest on osx', async () => { os.platform = 'darwin'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken'); expect(match).toBeDefined(); @@ -142,7 +145,7 @@ describe('setup-go', () => { it('can find 1.9 from manifest on linux', async () => { os.platform = 'linux'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken'); expect(match).toBeDefined(); @@ -155,7 +158,7 @@ describe('setup-go', () => { it('can find 1.9 from manifest on windows', async () => { os.platform = 'win32'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken'); expect(match).toBeDefined(); @@ -367,7 +370,7 @@ describe('setup-go', () => { it('does not find a version that does not exist', async () => { os.platform = 'linux'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); inputs['go-version'] = '9.99.9'; @@ -381,7 +384,7 @@ describe('setup-go', () => { it('downloads a version from a manifest match', async () => { os.platform = 'linux'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); let versionSpec = '1.12.16'; @@ -418,7 +421,7 @@ describe('setup-go', () => { it('downloads a major and minor from a manifest match', async () => { os.platform = 'linux'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); let versionSpec = '1.12'; @@ -453,7 +456,7 @@ describe('setup-go', () => { expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); }); - it('falls back to a version from node dist', async () => { + it('falls back to a version from go dist', async () => { os.platform = 'linux'; os.arch = 'x64'; @@ -694,7 +697,7 @@ describe('setup-go', () => { it('check latest version and install it from manifest', async () => { os.platform = 'linux'; - os.arch = 'x64'; + sysGetArchSpy.mockImplementationOnce(() => 'x64'); const versionSpec = '1.17'; const patchVersion = '1.17.6'; @@ -879,5 +882,40 @@ exclude example.com/thismodule v1.3.0 `::error::The specified go version file at: go.mod does not exist${osm.EOL}` ); }); + + it('acquires specified architecture of go', async () => { + for (const {arch, version, osSpec} of [ + {arch: 'amd64', version: '1.13.7', osSpec: 'linux'}, + {arch: 'armv6l', version: '1.12.2', osSpec: 'linux'} + ]) { + os.platform = osSpec; + os.arch = arch; + + const fileExtension = os.platform === 'win32' ? 'zip' : 'tar.gz'; + + const platform = os.platform === 'win32' ? 'win' : os.platform; + + inputs['go-version'] = version; + inputs['architecture'] = arch; + + let expectedUrl = + platform === 'win32' + ? `https://github.com/actions/go-versions/releases/download/${version}/go-${version}-${platform}-${arch}.${fileExtension}` + : `https://storage.googleapis.com/golang/go${version}.${osSpec}-${arch}.${fileExtension}`; + + // ... but not in the local cache + findSpy.mockImplementation(() => ''); + + dlSpy.mockImplementation(async () => '/some/temp/path'); + let toolPath = path.normalize(`/cache/go/${version}/${arch}`); + cacheSpy.mockImplementation(async () => toolPath); + + await main.run(); + + expect(logSpy).toHaveBeenCalledWith( + `Acquiring go${version} from ${expectedUrl}` + ); + } + }, 100000); }); }); diff --git a/action.yml b/action.yml index a8d7548..5310a11 100644 --- a/action.yml +++ b/action.yml @@ -17,6 +17,8 @@ inputs: default: false cache-dependency-path: description: 'Used to specify the path to a dependency file - go.sum' + architecture: + description: 'Target architecture for Go to use. Examples: x86, x64. Will use system architecture by default.' outputs: go-version: description: 'The installed Go version. Useful when given a version range as input.' diff --git a/dist/setup/index.js b/dist/setup/index.js index f598dfd..bac12fd 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -62858,13 +62858,12 @@ const httpm = __importStar(__nccwpck_require__(6255)); const sys = __importStar(__nccwpck_require__(4300)); const fs_1 = __importDefault(__nccwpck_require__(7147)); const os_1 = __importDefault(__nccwpck_require__(2037)); -function getGo(versionSpec, checkLatest, auth) { +function getGo(versionSpec, checkLatest, auth, arch = sys.getArch()) { return __awaiter(this, void 0, void 0, function* () { let osPlat = os_1.default.platform(); - let osArch = os_1.default.arch(); if (checkLatest) { core.info('Attempting to resolve the latest version from the manifest...'); - const resolvedVersion = yield resolveVersionFromManifest(versionSpec, true, auth); + const resolvedVersion = yield resolveVersionFromManifest(versionSpec, true, auth, arch); if (resolvedVersion) { versionSpec = resolvedVersion; core.info(`Resolved as '${versionSpec}'`); @@ -62888,9 +62887,9 @@ function getGo(versionSpec, checkLatest, auth) { // Try download from internal distribution (popular versions only) // try { - info = yield getInfoFromManifest(versionSpec, true, auth); + info = yield getInfoFromManifest(versionSpec, true, auth, arch); if (info) { - downloadPath = yield installGoVersion(info, auth); + downloadPath = yield installGoVersion(info, auth, arch); } else { core.info('Not found in manifest. Falling back to download directly from Go'); @@ -62911,13 +62910,13 @@ function getGo(versionSpec, checkLatest, auth) { // Download from storage.googleapis.com // if (!downloadPath) { - info = yield getInfoFromDist(versionSpec); + info = yield getInfoFromDist(versionSpec, arch); if (!info) { - throw new Error(`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`); + throw new Error(`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${arch}.`); } try { core.info('Install from dist'); - downloadPath = yield installGoVersion(info, undefined); + downloadPath = yield installGoVersion(info, undefined, arch); } catch (err) { throw new Error(`Failed to download version ${versionSpec}: ${err}`); @@ -62927,10 +62926,10 @@ function getGo(versionSpec, checkLatest, auth) { }); } exports.getGo = getGo; -function resolveVersionFromManifest(versionSpec, stable, auth) { +function resolveVersionFromManifest(versionSpec, stable, auth, arch) { return __awaiter(this, void 0, void 0, function* () { try { - const info = yield getInfoFromManifest(versionSpec, stable, auth); + const info = yield getInfoFromManifest(versionSpec, stable, auth, arch); return info === null || info === void 0 ? void 0 : info.resolvedVersion; } catch (err) { @@ -62939,7 +62938,7 @@ function resolveVersionFromManifest(versionSpec, stable, auth) { } }); } -function installGoVersion(info, auth) { +function installGoVersion(info, auth, arch) { return __awaiter(this, void 0, void 0, function* () { core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); // Windows requires that we keep the extension (.zip) for extraction @@ -62954,7 +62953,7 @@ function installGoVersion(info, auth) { extPath = path.join(extPath, 'go'); } core.info('Adding to the cache ...'); - const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion)); + const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion), arch); core.info(`Successfully cached go to ${cachedDir}`); return cachedDir; }); @@ -62973,12 +62972,12 @@ function extractGoArchive(archivePath) { }); } exports.extractGoArchive = extractGoArchive; -function getInfoFromManifest(versionSpec, stable, auth) { +function getInfoFromManifest(versionSpec, stable, auth, arch = sys.getArch()) { return __awaiter(this, void 0, void 0, function* () { let info = null; const releases = yield tc.getManifestFromRepo('actions', 'go-versions', auth, 'main'); core.info(`matching ${versionSpec}...`); - const rel = yield tc.findFromManifest(versionSpec, stable, releases); + const rel = yield tc.findFromManifest(versionSpec, stable, releases, arch); if (rel && rel.files.length > 0) { info = {}; info.type = 'manifest'; @@ -62990,10 +62989,10 @@ function getInfoFromManifest(versionSpec, stable, auth) { }); } exports.getInfoFromManifest = getInfoFromManifest; -function getInfoFromDist(versionSpec) { +function getInfoFromDist(versionSpec, arch) { return __awaiter(this, void 0, void 0, function* () { let version; - version = yield findMatch(versionSpec); + version = yield findMatch(versionSpec, arch); if (!version) { return null; } @@ -63006,9 +63005,9 @@ function getInfoFromDist(versionSpec) { }; }); } -function findMatch(versionSpec) { +function findMatch(versionSpec, arch = sys.getArch()) { return __awaiter(this, void 0, void 0, function* () { - let archFilter = sys.getArch(); + let archFilter = translateArchToDistUrl(arch); let platFilter = sys.getPlatform(); let result; let match; @@ -63088,6 +63087,14 @@ function parseGoVersionFile(versionFilePath) { return contents.trim(); } exports.parseGoVersionFile = parseGoVersionFile; +function translateArchToDistUrl(arch) { + switch (arch) { + case 'arm': + return 'armv6l'; + default: + return arch; + } +} /***/ }), diff --git a/src/installer.ts b/src/installer.ts index 58c9428..4e69bd9 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -32,17 +32,18 @@ export interface IGoVersionInfo { export async function getGo( versionSpec: string, checkLatest: boolean, - auth: string | undefined + auth: string | undefined, + arch = sys.getArch() ) { let osPlat: string = os.platform(); - let osArch: string = os.arch(); if (checkLatest) { core.info('Attempting to resolve the latest version from the manifest...'); const resolvedVersion = await resolveVersionFromManifest( versionSpec, true, - auth + auth, + arch ); if (resolvedVersion) { versionSpec = resolvedVersion; @@ -68,9 +69,9 @@ export async function getGo( // Try download from internal distribution (popular versions only) // try { - info = await getInfoFromManifest(versionSpec, true, auth); + info = await getInfoFromManifest(versionSpec, true, auth, arch); if (info) { - downloadPath = await installGoVersion(info, auth); + downloadPath = await installGoVersion(info, auth, arch); } else { core.info( 'Not found in manifest. Falling back to download directly from Go' @@ -95,16 +96,16 @@ export async function getGo( // Download from storage.googleapis.com // if (!downloadPath) { - info = await getInfoFromDist(versionSpec); + info = await getInfoFromDist(versionSpec, arch); if (!info) { throw new Error( - `Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.` + `Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${arch}.` ); } try { core.info('Install from dist'); - downloadPath = await installGoVersion(info, undefined); + downloadPath = await installGoVersion(info, undefined, arch); } catch (err) { throw new Error(`Failed to download version ${versionSpec}: ${err}`); } @@ -116,10 +117,11 @@ export async function getGo( async function resolveVersionFromManifest( versionSpec: string, stable: boolean, - auth: string | undefined + auth: string | undefined, + arch: string ): Promise { try { - const info = await getInfoFromManifest(versionSpec, stable, auth); + const info = await getInfoFromManifest(versionSpec, stable, auth, arch); return info?.resolvedVersion; } catch (err) { core.info('Unable to resolve a version from the manifest...'); @@ -129,7 +131,8 @@ async function resolveVersionFromManifest( async function installGoVersion( info: IGoVersionInfo, - auth: string | undefined + auth: string | undefined, + arch: string ): Promise { core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); @@ -151,7 +154,8 @@ async function installGoVersion( const cachedDir = await tc.cacheDir( extPath, 'go', - makeSemver(info.resolvedVersion) + makeSemver(info.resolvedVersion), + arch ); core.info(`Successfully cached go to ${cachedDir}`); return cachedDir; @@ -173,7 +177,8 @@ export async function extractGoArchive(archivePath: string): Promise { export async function getInfoFromManifest( versionSpec: string, stable: boolean, - auth: string | undefined + auth: string | undefined, + arch = sys.getArch() ): Promise { let info: IGoVersionInfo | null = null; const releases = await tc.getManifestFromRepo( @@ -183,7 +188,7 @@ export async function getInfoFromManifest( 'main' ); core.info(`matching ${versionSpec}...`); - const rel = await tc.findFromManifest(versionSpec, stable, releases); + const rel = await tc.findFromManifest(versionSpec, stable, releases, arch); if (rel && rel.files.length > 0) { info = {}; @@ -197,10 +202,11 @@ export async function getInfoFromManifest( } async function getInfoFromDist( - versionSpec: string + versionSpec: string, + arch: string ): Promise { let version: IGoVersion | undefined; - version = await findMatch(versionSpec); + version = await findMatch(versionSpec, arch); if (!version) { return null; } @@ -216,9 +222,10 @@ async function getInfoFromDist( } export async function findMatch( - versionSpec: string + versionSpec: string, + arch = sys.getArch() ): Promise { - let archFilter = sys.getArch(); + let archFilter = translateArchToDistUrl(arch); let platFilter = sys.getPlatform(); let result: IGoVersion | undefined; @@ -316,3 +323,12 @@ export function parseGoVersionFile(versionFilePath: string): string { return contents.trim(); } + +function translateArchToDistUrl(arch: string): string { + switch (arch) { + case 'arm': + return 'armv6l'; + default: + return arch; + } +}