From 7d28d8663b46d572ab14451b6c44864e754db40e Mon Sep 17 00:00:00 2001 From: Milos Pantic <101411245+panticmilos@users.noreply.github.com> Date: Fri, 12 Aug 2022 12:29:48 +0200 Subject: [PATCH] Add support for arm32 go arch (#253) --- .github/workflows/versions.yml | 19 ++++++++++++- __tests__/setup-go.test.ts | 37 ++++++++++++++++++++++++- action.yml | 2 ++ dist/setup/index.js | 50 +++++++++++++++++++--------------- src/installer.ts | 45 +++++++++++++++++------------- src/main.ts | 14 +++++++++- src/system.ts | 6 ++-- 7 files changed, 127 insertions(+), 46 deletions(-) diff --git a/.github/workflows/versions.yml b/.github/workflows/versions.yml index 12c711e3f..3c74bd41d 100644 --- a/.github/workflows/versions.yml +++ b/.github/workflows/versions.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: os: [macos-latest, windows-latest, ubuntu-latest] - go: [1.12, 1.13, 1.14] + go: [1.17, 1.18, 1.19] steps: - name: Checkout uses: actions/checkout@v3 @@ -107,3 +107,20 @@ jobs: - name: verify go run: __tests__/verify-go.sh ${{ matrix.go }} shell: bash + + architecture: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + go-version: [1.16, 1.17] + steps: + - uses: actions/checkout@v3 + - name: Setup Go and check latest + uses: ./ + with: + go-version: ${{ matrix.go-version }} + architecture: x64 + - name: Verify Go + run: go version \ No newline at end of file diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 9e390755d..4378b0ec5 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -453,7 +453,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'; @@ -879,5 +879,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 a8d7548f1..5310a111f 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 f598dfd96..08d77d5fd 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 = os_1.default.arch()) { 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}'`); @@ -62875,7 +62874,7 @@ function getGo(versionSpec, checkLatest, auth) { } // check cache let toolPath; - toolPath = tc.find('go', versionSpec); + toolPath = tc.find('go', versionSpec, arch); // If not found in cache, download if (toolPath) { core.info(`Found in cache @ ${toolPath}`); @@ -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 = os_1.default.arch()) { 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 = os_1.default.arch()) { return __awaiter(this, void 0, void 0, function* () { - let archFilter = sys.getArch(); + let archFilter = sys.getArch(arch); let platFilter = sys.getPlatform(); let result; let match; @@ -63139,6 +63138,7 @@ const cache_restore_1 = __nccwpck_require__(9517); const cache_utils_1 = __nccwpck_require__(1678); const child_process_1 = __importDefault(__nccwpck_require__(2081)); const fs_1 = __importDefault(__nccwpck_require__(7147)); +const os_1 = __importDefault(__nccwpck_require__(2037)); function run() { return __awaiter(this, void 0, void 0, function* () { try { @@ -63149,11 +63149,15 @@ function run() { const versionSpec = resolveVersionInput(); const cache = core.getBooleanInput('cache'); core.info(`Setup go version spec ${versionSpec}`); + let arch = core.getInput('architecture'); + if (!arch) { + arch = os_1.default.arch(); + } if (versionSpec) { let token = core.getInput('token'); let auth = !token || cache_utils_1.isGhes() ? undefined : `token ${token}`; const checkLatest = core.getBooleanInput('check-latest'); - const installDir = yield installer.getGo(versionSpec, checkLatest, auth); + const installDir = yield installer.getGo(versionSpec, checkLatest, auth, arch); core.addPath(path_1.default.join(installDir, 'bin')); core.info('Added go to the path'); const version = installer.makeSemver(versionSpec); @@ -63286,9 +63290,8 @@ function getPlatform() { return plat; } exports.getPlatform = getPlatform; -function getArch() { +function getArch(arch) { // 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'. - let arch = os.arch(); // wants amd64, 386, arm64, armv61, ppc641e, s390x // currently not supported by runner but future proofed mapping switch (arch) { @@ -63301,6 +63304,9 @@ function getArch() { case 'x32': arch = '386'; break; + case 'arm': + arch = 'armv6l'; + break; } return arch; } diff --git a/src/installer.ts b/src/installer.ts index 58c94285e..6335dbdc8 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 = os.arch() ) { 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; @@ -54,7 +55,7 @@ export async function getGo( // check cache let toolPath: string; - toolPath = tc.find('go', versionSpec); + toolPath = tc.find('go', versionSpec, arch); // If not found in cache, download if (toolPath) { core.info(`Found in cache @ ${toolPath}`); @@ -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 = os.arch() ): 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 = os.arch() ): Promise { - let archFilter = sys.getArch(); + let archFilter = sys.getArch(arch); let platFilter = sys.getPlatform(); let result: IGoVersion | undefined; diff --git a/src/main.ts b/src/main.ts index 0649dec5b..8648d4def 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import {restoreCache} from './cache-restore'; import {isGhes, isCacheFeatureAvailable} from './cache-utils'; import cp from 'child_process'; import fs from 'fs'; +import os from 'os'; export async function run() { try { @@ -19,12 +20,23 @@ export async function run() { const cache = core.getBooleanInput('cache'); core.info(`Setup go version spec ${versionSpec}`); + let arch = core.getInput('architecture'); + + if (!arch) { + arch = os.arch(); + } + if (versionSpec) { let token = core.getInput('token'); let auth = !token || isGhes() ? undefined : `token ${token}`; const checkLatest = core.getBooleanInput('check-latest'); - const installDir = await installer.getGo(versionSpec, checkLatest, auth); + const installDir = await installer.getGo( + versionSpec, + checkLatest, + auth, + arch + ); core.addPath(path.join(installDir, 'bin')); core.info('Added go to the path'); diff --git a/src/system.ts b/src/system.ts index 6973f9998..3164a21b2 100644 --- a/src/system.ts +++ b/src/system.ts @@ -15,9 +15,8 @@ export function getPlatform(): string { return plat; } -export function getArch(): string { +export function getArch(arch: string): string { // 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'. - let arch: string = os.arch(); // wants amd64, 386, arm64, armv61, ppc641e, s390x // currently not supported by runner but future proofed mapping @@ -31,6 +30,9 @@ export function getArch(): string { case 'x32': arch = '386'; break; + case 'arm': + arch = 'armv6l'; + break; } return arch;