From ce1ecde76dbc21a2102dc5c8ad9599a4c55d70db Mon Sep 17 00:00:00 2001 From: Jonathan Matthews Date: Wed, 2 Aug 2023 14:12:16 +0100 Subject: [PATCH] action: query the Go proxy for CUE versions We believe that the cause of intermittent GitHub API 403 responses, which are now exposed to the Action consumer and not masked, is that this Action doesn't use a GITHUB_TOKEN (even when provided as an envvar) to authenticate to the GitHub API. Therefore, all our API requests are unauthenticated, which are nominally rate-limited at a level which shouldn't affect any consumer. However, they *do* affect consumers: ourselves, in testing, and also in production. We hypothesise that this is because GitHub-hosted GitHub Actions runners are issued IP addresses from some shared pool, thus any requests "we" make are counted against a rate limit that a previous user may have already used up. To get round this, this commit changes the Action's behaviour to use the Go Proxy as the upstream source of truth of which CUE version is the "latest", instead of the GitHub API. This has the advantage of harmonising the Action and the Go CLI's concepts of "latest". An alternative would be to teach this Action's API requests to use the GITHUB_TOKEN, if provided. This would have the downside of needing the Action's consumers to provide this in their workflows, so we avoid this alternative for now. Signed-off-by: Jonathan Matthews --- __tests__/run.test.ts | 16 +--------------- dist/index.js | 13 +++++-------- package-lock.json | 3 +-- package.json | 5 ++--- src/run.ts | 13 +++++-------- 5 files changed, 14 insertions(+), 36 deletions(-) diff --git a/__tests__/run.test.ts b/__tests__/run.test.ts index e4850b7..53e5c9e 100644 --- a/__tests__/run.test.ts +++ b/__tests__/run.test.ts @@ -129,21 +129,7 @@ describe('Testing all functions in run file.', () => { test('getLatestCuectlVersion() must download latest version file, read version and return it', async () => { jest.spyOn(toolCache, 'downloadTool').mockResolvedValue('pathToTool'); - const response = JSON.stringify( - [ - { - 'tag_name': 'v0.2.0' - }, { - 'tag_name': 'v0.3.0-rc.2' - }, { - 'tag_name': 'v0.5.0' - }, { - 'tag_name': 'v0.4.0' - }, { - 'tag_name': 'v0.5.0-alpha.1' - } - ] - ); + const response = '{"Version":"v0.5.0","Time":"2023-04-12T11:01:31Z","Origin":{"VCS":"git","URL":"https://review.gerrithub.io/cue-lang/cue","Ref":"refs/tags/v0.5.0","Hash":"d780488159bd082f9f9d027ab42dd4d9b5d95d5e"}}'; jest.spyOn(fs, 'readFileSync').mockReturnValue(response); expect(await run.getLatestCuectlVersion()).toBe('v0.5.0'); diff --git a/dist/index.js b/dist/index.js index 82c1bb3..18710c4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -7184,9 +7184,8 @@ const util = __nccwpck_require__(3837); const fs = __nccwpck_require__(7147); const toolCache = __nccwpck_require__(7784); const core = __nccwpck_require__(2186); -const semver = __nccwpck_require__(5911); const cuectlToolName = 'cue'; -const cuectlAllReleasesUrl = 'https://api.github.com/repos/cue-lang/cue/releases'; +const cuectlLatestReleaseUrl = 'https://proxy.golang.org/cuelang.org/go/@latest'; function getExecutableExtension() { if (os.type().match(/^Win/)) { return '.exe'; @@ -7205,14 +7204,12 @@ exports.getCuectlOSArchitecture = getCuectlOSArchitecture; function getLatestCuectlVersion() { return __awaiter(this, void 0, void 0, function* () { try { - const downloadPath = yield toolCache.downloadTool(cuectlAllReleasesUrl); - const responseArray = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim()); - const versionArray = responseArray.map(function (version) { return semver.clean(version.tag_name); }); - const latestRelease = semver.maxSatisfying(versionArray, "*"); // this strips pre-release versions - return "v" + latestRelease; + const downloadPath = yield toolCache.downloadTool(cuectlLatestReleaseUrl); + const response = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim()); + return response.Version; } catch (error) { - throw new Error(util.format("Cannot get the latest cue releases infos from %s. Error %s.", cuectlAllReleasesUrl, error)); + throw new Error(util.format("Cannot get the latest cue releases infos from %s. Error %s.", cuectlLatestReleaseUrl, error)); } }); } diff --git a/package-lock.json b/package-lock.json index 12eed04..acc953c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "dependencies": { "@actions/core": "^1.10.0", "@actions/exec": "^1.1.1", - "@actions/tool-cache": "^1.7.2", - "semver": "^6.3.0" + "@actions/tool-cache": "^1.7.2" }, "devDependencies": { "@types/jest": "^27.5.2", diff --git a/package.json b/package.json index 8f7c167..c9ab0aa 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "dependencies": { "@actions/core": "^1.10.0", "@actions/exec": "^1.1.1", - "@actions/tool-cache": "^1.7.2", - "semver": "^6.3.0" + "@actions/tool-cache": "^1.7.2" } -} \ No newline at end of file +} diff --git a/src/run.ts b/src/run.ts index a3d530d..d9faab7 100644 --- a/src/run.ts +++ b/src/run.ts @@ -19,10 +19,9 @@ import * as fs from 'fs'; import * as toolCache from '@actions/tool-cache'; import * as core from '@actions/core'; -import * as semver from 'semver'; const cuectlToolName = 'cue'; -const cuectlAllReleasesUrl = 'https://api.github.com/repos/cue-lang/cue/releases'; +const cuectlLatestReleaseUrl = 'https://proxy.golang.org/cuelang.org/go/@latest'; export function getExecutableExtension(): string { if (os.type().match(/^Win/)) { @@ -41,13 +40,11 @@ export function getCuectlOSArchitecture(): string { export async function getLatestCuectlVersion(): Promise { try { - const downloadPath = await toolCache.downloadTool(cuectlAllReleasesUrl); - const responseArray = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim()); - const versionArray = responseArray.map(function (version) { return semver.clean(version.tag_name) }); - const latestRelease = semver.maxSatisfying(versionArray, "*"); // this strips pre-release versions - return "v" + latestRelease; + const downloadPath = await toolCache.downloadTool(cuectlLatestReleaseUrl); + const response = JSON.parse(fs.readFileSync(downloadPath, 'utf8').toString().trim()); + return response.Version; } catch (error) { - throw new Error(util.format("Cannot get the latest cue releases infos from %s. Error %s.", cuectlAllReleasesUrl, error)); + throw new Error(util.format("Cannot get the latest cue releases infos from %s. Error %s.", cuectlLatestReleaseUrl, error)); } }