From 5320ddc712eaa6779357e60b178a6d2ea511b710 Mon Sep 17 00:00:00 2001 From: Tobias Gabriel Date: Tue, 20 Aug 2024 11:39:45 +0200 Subject: [PATCH] feat: fallback to "raw" endpoint for manifest when rate limit is reached --- __tests__/setup-go.test.ts | 23 +++++++++++++++++++++ dist/setup/index.js | 30 +++++++++++++++++++++++++++- src/installer.ts | 41 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/__tests__/setup-go.test.ts b/__tests__/setup-go.test.ts index 70f2166..dcf33ec 100644 --- a/__tests__/setup-go.test.ts +++ b/__tests__/setup-go.test.ts @@ -7,6 +7,7 @@ import osm, {type} from 'os'; import path from 'path'; import * as main from '../src/main'; import * as im from '../src/installer'; +import * as httpm from '@actions/http-client'; import goJsonData from './data/golang-dl.json'; import matchers from '../matchers.json'; @@ -46,6 +47,7 @@ describe('setup-go', () => { let execSpy: jest.SpyInstance; let getManifestSpy: jest.SpyInstance; let getAllVersionsSpy: jest.SpyInstance; + let httpmGetJsonSpy: 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) @@ -90,6 +92,9 @@ describe('setup-go', () => { getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); getAllVersionsSpy = jest.spyOn(im, 'getManifest'); + // httm + httpmGetJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson') + // io whichSpy = jest.spyOn(io, 'which'); existsSpy = jest.spyOn(fs, 'existsSync'); @@ -151,6 +156,23 @@ describe('setup-go', () => { ); }); + it('should return manifest from repo', async () => { + const manifest = await im.getManifest(undefined); + expect(manifest).toEqual(goTestManifest); + }); + + it('should return manifest from raw URL if repo fetch fails', async () => { + getManifestSpy.mockRejectedValue( + new Error('Fetch failed') + ); + httpmGetJsonSpy.mockResolvedValue({ + result: goTestManifest + }); + const manifest = await im.getManifest(undefined); + expect(httpmGetJsonSpy).toHaveBeenCalled(); + expect(manifest).toEqual(goTestManifest); + }); + it('can find 1.9 from manifest on linux', async () => { os.platform = 'linux'; os.arch = 'x64'; @@ -790,6 +812,7 @@ describe('setup-go', () => { getManifestSpy.mockImplementation(() => { throw new Error('Unable to download manifest'); }); + httpmGetJsonSpy.mockRejectedValue(new Error('Unable to download manifest from raw URL')); getAllVersionsSpy.mockImplementationOnce(() => undefined); dlSpy.mockImplementation(async () => '/some/temp/path'); diff --git a/dist/setup/index.js b/dist/setup/index.js index 9ad3784..1b5e76f 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -88254,6 +88254,10 @@ const sys = __importStar(__nccwpck_require__(5632)); const fs_1 = __importDefault(__nccwpck_require__(7147)); const os_1 = __importDefault(__nccwpck_require__(2037)); const utils_1 = __nccwpck_require__(1314); +const MANIFEST_REPO_OWNER = 'actions'; +const MANIFEST_REPO_NAME = 'go-versions'; +const MANIFEST_REPO_BRANCH = 'main'; +const MANIFEST_URL = `https://raw.githubusercontent.com/${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}/${MANIFEST_REPO_BRANCH}/versions-manifest.json`; function getGo(versionSpec_1, checkLatest_1, auth_1) { return __awaiter(this, arguments, void 0, function* (versionSpec, checkLatest, auth, arch = os_1.default.arch()) { var _a; @@ -88428,10 +88432,34 @@ function extractGoArchive(archivePath) { exports.extractGoArchive = extractGoArchive; function getManifest(auth) { return __awaiter(this, void 0, void 0, function* () { - return tc.getManifestFromRepo('actions', 'go-versions', auth, 'main'); + try { + return yield getManifestFromRepo(auth); + } + catch (err) { + core.debug('Fetching the manifest via the API failed.'); + if (err instanceof Error) { + core.debug(err.message); + } + } + return yield getManifestFromURL(); }); } exports.getManifest = getManifest; +function getManifestFromRepo(auth) { + core.debug(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`); + return tc.getManifestFromRepo(MANIFEST_REPO_OWNER, MANIFEST_REPO_NAME, auth, MANIFEST_REPO_BRANCH); +} +function getManifestFromURL() { + return __awaiter(this, void 0, void 0, function* () { + core.debug('Falling back to fetching the manifest using raw URL.'); + const http = new httpm.HttpClient('tool-cache'); + const response = yield http.getJson(MANIFEST_URL); + if (!response.result) { + throw new Error(`Unable to get manifest from ${MANIFEST_URL}`); + } + return response.result; + }); +} function getInfoFromManifest(versionSpec_1, stable_1, auth_1) { return __awaiter(this, arguments, void 0, function* (versionSpec, stable, auth, arch = os_1.default.arch(), manifest) { let info = null; diff --git a/src/installer.ts b/src/installer.ts index 817c334..c8fc028 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -8,6 +8,12 @@ import fs from 'fs'; import os from 'os'; import {StableReleaseAlias} from './utils'; +const MANIFEST_REPO_OWNER = 'actions'; +const MANIFEST_REPO_NAME = 'go-versions'; +const MANIFEST_REPO_BRANCH = 'main'; +const MANIFEST_URL = `https://raw.githubusercontent.com/${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}/${MANIFEST_REPO_BRANCH}/versions-manifest.json`; + + type InstallationType = 'dist' | 'manifest'; export interface IGoVersionFile { @@ -274,8 +280,39 @@ export async function extractGoArchive(archivePath: string): Promise { return extPath; } -export async function getManifest(auth: string | undefined) { - return tc.getManifestFromRepo('actions', 'go-versions', auth, 'main'); +export async function getManifest(auth: string | undefined): Promise { + try { + return await getManifestFromRepo(auth); + } catch (err) { + core.debug('Fetching the manifest via the API failed.'); + if (err instanceof Error) { + core.debug(err.message); + } + } + return await getManifestFromURL(); +} + +function getManifestFromRepo(auth: string | undefined): Promise { + core.debug( + `Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}` + ); + return tc.getManifestFromRepo( + MANIFEST_REPO_OWNER, + MANIFEST_REPO_NAME, + auth, + MANIFEST_REPO_BRANCH + ); +} + +async function getManifestFromURL(): Promise { + core.debug('Falling back to fetching the manifest using raw URL.'); + + const http: httpm.HttpClient = new httpm.HttpClient('tool-cache'); + const response = await http.getJson(MANIFEST_URL); + if (!response.result) { + throw new Error(`Unable to get manifest from ${MANIFEST_URL}`); + } + return response.result; } export async function getInfoFromManifest(