diff --git a/.github/package-lock.json b/.github/package-lock.json index d3d1c5d79799..455857b32699 100644 --- a/.github/package-lock.json +++ b/.github/package-lock.json @@ -17,6 +17,7 @@ "@actions/github-script": "github:actions/github-script", "@eslint/js": "^9.22.0", "@octokit/rest": "^22.0.0", + "@octokit/types": "^14.1.0", "@octokit/webhooks-types": "^7.5.1", "@tsconfig/node20": "^20.1.4", "@types/debug": "^4.1.12", @@ -1031,6 +1032,23 @@ "node": ">= 18" } }, + "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/core/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/endpoint": { "version": "9.0.6", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", @@ -1045,6 +1063,23 @@ "node": ">= 18" } }, + "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/endpoint/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/graphql": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", @@ -1060,13 +1095,30 @@ "node": ">= 18" } }, - "node_modules/@octokit/openapi-types": { + "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { "version": "24.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", "dev": true, "license": "MIT" }, + "node_modules/@octokit/graphql/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", + "dev": true, + "license": "MIT" + }, "node_modules/@octokit/plugin-paginate-rest": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", @@ -1164,6 +1216,23 @@ "@octokit/core": "5" } }, + "node_modules/@octokit/plugin-retry/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-retry/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/request": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", @@ -1195,6 +1264,40 @@ "node": ">= 18" } }, + "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/request-error/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/request/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/request/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/rest": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.0.tgz", @@ -1269,13 +1372,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/openapi-types": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", - "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", - "dev": true, - "license": "MIT" - }, "node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": { "version": "13.1.1", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.1.1.tgz", @@ -1351,16 +1447,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/types": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", - "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^25.1.0" - } - }, "node_modules/@octokit/rest/node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -1376,13 +1462,13 @@ "license": "ISC" }, "node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^24.2.0" + "@octokit/openapi-types": "^25.1.0" } }, "node_modules/@octokit/webhooks-types": { diff --git a/.github/package.json b/.github/package.json index 65cb98057057..f63ab04ff171 100644 --- a/.github/package.json +++ b/.github/package.json @@ -17,8 +17,9 @@ "devDependencies": { "@actions/github-script": "github:actions/github-script", "@eslint/js": "^9.22.0", - "@octokit/webhooks-types": "^7.5.1", "@octokit/rest": "^22.0.0", + "@octokit/types": "^14.1.0", + "@octokit/webhooks-types": "^7.5.1", "@tsconfig/node20": "^20.1.4", "@types/debug": "^4.1.12", "@types/js-yaml": "^4.0.9", diff --git a/.github/workflows/src/context.js b/.github/workflows/src/context.js index f32754fcb1b5..ab761e73c8ca 100644 --- a/.github/workflows/src/context.js +++ b/.github/workflows/src/context.js @@ -2,6 +2,7 @@ import { inspect } from "util"; import { PER_PAGE_MAX } from "../../shared/src/github.js"; +import { rateLimitHook } from "./github.js"; import { getIssueNumber } from "./issues.js"; /** @@ -30,6 +31,8 @@ export async function extractInputs(github, context, core) { core.debug(`context: ${JSON.stringify(context)}`); } + github.hook.after("request", rateLimitHook); + /** @type {{ owner: string, repo: string, head_sha: string, issue_number: number, run_id: number, details_url?: string }} */ let inputs; diff --git a/.github/workflows/src/github.js b/.github/workflows/src/github.js index 00876082464b..274341509649 100644 --- a/.github/workflows/src/github.js +++ b/.github/workflows/src/github.js @@ -100,3 +100,19 @@ export async function getWorkflowRuns(github, context, workflowName, ref) { .filter((run) => run.name === workflowName) .sort(invert(byDate((run) => run.updated_at))); } + +/** + * @param {import("@octokit/types").OctokitResponse} response + * @param {import("@octokit/types").RequestParameters & {url: string, method: string}} options + */ +export function rateLimitHook(response, options) { + const limits = { + method: options.method.toUpperCase(), + url: options.url, + limit: response.headers["x-ratelimit-limit"], + remaining: response.headers["x-ratelimit-remaining"], + reset: new Date(parseInt(response.headers["x-ratelimit-reset"] || "") * 1000), + }; + + console.log(`rate-limits: ${JSON.stringify(limits)}`); +} diff --git a/.github/workflows/test/context.test.js b/.github/workflows/test/context.test.js index ce90b9decd7c..f76bcd6c17ec 100644 --- a/.github/workflows/test/context.test.js +++ b/.github/workflows/test/context.test.js @@ -34,7 +34,7 @@ describe("extractInputs", () => { }, }; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual({ + await expect(extractInputs(createMockGithub(), context, createMockCore())).resolves.toEqual({ owner: "TestRepoOwnerLogin", repo: "TestRepoName", head_sha: "abc123", @@ -44,6 +44,8 @@ describe("extractInputs", () => { }); it("pull_request_target", async () => { + const github = createMockGithub(); + const context = { eventName: "pull_request_target", payload: { @@ -71,23 +73,23 @@ describe("extractInputs", () => { run_id: NaN, }; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual(expected); + await expect(extractInputs(github, context, createMockCore())).resolves.toEqual(expected); context.payload.action = "unlabeled"; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual(expected); + await expect(extractInputs(github, context, createMockCore())).resolves.toEqual(expected); context.payload.action = "opened"; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual(expected); + await expect(extractInputs(github, context, createMockCore())).resolves.toEqual(expected); context.payload.action = "synchronize"; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual(expected); + await expect(extractInputs(github, context, createMockCore())).resolves.toEqual(expected); context.payload.action = "reopened"; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual(expected); + await expect(extractInputs(github, context, createMockCore())).resolves.toEqual(expected); // Action not yet supported context.payload.action = "assigned"; - await expect(extractInputs(null, context, createMockCore())).rejects.toThrow(); + await expect(extractInputs(github, context, createMockCore())).rejects.toThrow(); }); it("issue_comment:edited", async () => { @@ -140,7 +142,7 @@ describe("extractInputs", () => { }, }; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual({ + await expect(extractInputs(createMockGithub(), context, createMockCore())).resolves.toEqual({ owner: "TestRepoOwnerLogin", repo: "TestRepoName", head_sha: "", @@ -157,7 +159,7 @@ describe("extractInputs", () => { }, }; - await expect(extractInputs(null, context, createMockCore())).rejects.toThrow(); + await expect(extractInputs(createMockGithub(), context, createMockCore())).rejects.toThrow(); }); it("workflow_run:completed:pull_request (same repo)", async () => { @@ -180,7 +182,7 @@ describe("extractInputs", () => { }, }; - await expect(extractInputs(null, context, createMockCore())).resolves.toEqual({ + await expect(extractInputs(createMockGithub(), context, createMockCore())).resolves.toEqual({ owner: "TestRepoOwnerLogin", repo: "TestRepoName", head_sha: "abc123", diff --git a/.github/workflows/test/mocks.js b/.github/workflows/test/mocks.js index 555bcb3d295a..b576ed4d3d71 100644 --- a/.github/workflows/test/mocks.js +++ b/.github/workflows/test/mocks.js @@ -4,6 +4,9 @@ import { vi } from "vitest"; // Partial mock of `github` parameter passed into github-script actions export function createMockGithub() { return { + hook: { + after: vi.fn(), + }, paginate: async (func, params) => { // Assume all test data fits in single page const data = (await func(params)).data;