From e8c15cfa3fbed666708f7be230848a3498f39d82 Mon Sep 17 00:00:00 2001 From: Andrew Taylor Date: Fri, 2 Feb 2024 08:45:21 -0800 Subject: [PATCH 1/3] Install @octokit/plugin-paginate-graphql --- package-lock.json | 18 ++++++++++++++++++ package.json | 1 + 2 files changed, 19 insertions(+) diff --git a/package-lock.json b/package-lock.json index 45d70d0..ea2bdf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.0", + "@octokit/plugin-paginate-graphql": "^4.0.0", "node-fetch": "^3.3.2" }, "devDependencies": { @@ -1245,6 +1246,17 @@ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz", "integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==" }, + "node_modules/@octokit/plugin-paginate-graphql": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-4.0.0.tgz", + "integrity": "sha512-7HcYW5tP7/Z6AETAPU14gp5H5KmCPT3hmJrS/5tO7HIgbwenYmgw4OY9Ma54FDySuxMwD+wsJlxtuGWwuZuItA==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, "node_modules/@octokit/plugin-paginate-rest": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz", @@ -5640,6 +5652,12 @@ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz", "integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==" }, + "@octokit/plugin-paginate-graphql": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-4.0.0.tgz", + "integrity": "sha512-7HcYW5tP7/Z6AETAPU14gp5H5KmCPT3hmJrS/5tO7HIgbwenYmgw4OY9Ma54FDySuxMwD+wsJlxtuGWwuZuItA==", + "requires": {} + }, "@octokit/plugin-paginate-rest": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz", diff --git a/package.json b/package.json index 6a5f25c..b61f880 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.0", + "@octokit/plugin-paginate-graphql": "^4.0.0", "node-fetch": "^3.3.2" }, "devDependencies": { From cb0eff7bf29307c18a7ff5172022ceb3b927b628 Mon Sep 17 00:00:00 2001 From: Andrew Taylor Date: Fri, 2 Feb 2024 08:45:26 -0800 Subject: [PATCH 2/3] Paginate pull request comments query Use [`@octokit/plugin-paginate-graphql`](https://github.com/octokit/plugin-paginate-graphql.js) with [plugin support from `@actions/core`](https://github.com/octokit/core.js?tab=readme-ov-file#plugins) --- src/github.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/github.js b/src/github.js index 88e0e6b..6f63612 100644 --- a/src/github.js +++ b/src/github.js @@ -1,10 +1,19 @@ import * as core from "@actions/core"; -import * as github from "@actions/github"; +import {paginateGraphql} from "@octokit/plugin-paginate-graphql"; +import { GitHub as OctokitPluginUtil, getOctokitOptions } from '@actions/github/lib/utils' export default class GitHub { constructor() { const token = core.getInput("token") || process.env.GITHUB_TOKEN || ""; - this.octokit = github.getOctokit(token); + // Exit early if no token is provided. + if (token.length === 0) { + core.error("No GitHub token provided."); + } + + // Create a new Octokit class instance with the paginateGraphql plugin. + this.octokitInstance = OctokitPluginUtil.plugin(paginateGraphql); + // Instantiate the Octokit class with the paginateGraphql plugin. + this.octokit = this.octokitInstance(getOctokitOptions(token)); } /** @@ -34,8 +43,8 @@ export default class GitHub { async getContributorData({ owner, repo, prNumber }) { core.info('Gathering contributor list.'); - const data = await this.octokit.graphql( - `query($owner:String!, $name:String!, $prNumber:Int!) { + const data = await this.octokit.graphql.paginateGraphql( + `query($owner:String!, $name:String!, $prNumber:Int!, $cursor: String) { repository(owner:$owner, name:$name) { pullRequest(number:$prNumber) { commits(first: 100) { @@ -67,6 +76,10 @@ export default class GitHub { login } } + pageInfo { + hasNextPage + endCursor + } } closingIssuesReferences(first:100){ nodes { From f60714ed5e6d3a7dec903f5342818d1a3991db17 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Mon, 5 Feb 2024 10:10:11 -0500 Subject: [PATCH 3/3] Add some test values. --- dist/index.js | 248 +++++++++++++++++++++++++++++++++++++++++++++++++- src/github.js | 6 +- 2 files changed, 249 insertions(+), 5 deletions(-) diff --git a/dist/index.js b/dist/index.js index 0b2e594..97381e2 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2866,6 +2866,225 @@ function withCustomRequest(customRequest) { 0 && (0); +/***/ }), + +/***/ 5883: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// pkg/dist-src/index.js +var dist_src_exports = {}; +__export(dist_src_exports, { + paginateGraphql: () => paginateGraphql +}); +module.exports = __toCommonJS(dist_src_exports); +var import_core3 = __nccwpck_require__(6762); + +// pkg/dist-src/errors.js +var generateMessage = (path, cursorValue) => `The cursor at "${path.join( + "," +)}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`; +var MissingCursorChange = class extends Error { + constructor(pageInfo, cursorValue) { + super(generateMessage(pageInfo.pathInQuery, cursorValue)); + this.pageInfo = pageInfo; + this.cursorValue = cursorValue; + this.name = "MissingCursorChangeError"; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } +}; +var MissingPageInfo = class extends Error { + constructor(response) { + super( + `No pageInfo property found in response. Please make sure to specify the pageInfo in your query. Response-Data: ${JSON.stringify( + response, + null, + 2 + )}` + ); + this.response = response; + this.name = "MissingPageInfo"; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } +}; + +// pkg/dist-src/object-helpers.js +var isObject = (value) => Object.prototype.toString.call(value) === "[object Object]"; +function findPaginatedResourcePath(responseData) { + const paginatedResourcePath = deepFindPathToProperty( + responseData, + "pageInfo" + ); + if (paginatedResourcePath.length === 0) { + throw new MissingPageInfo(responseData); + } + return paginatedResourcePath; +} +var deepFindPathToProperty = (object, searchProp, path = []) => { + for (const key of Object.keys(object)) { + const currentPath = [...path, key]; + const currentValue = object[key]; + if (currentValue.hasOwnProperty(searchProp)) { + return currentPath; + } + if (isObject(currentValue)) { + const result = deepFindPathToProperty( + currentValue, + searchProp, + currentPath + ); + if (result.length > 0) { + return result; + } + } + } + return []; +}; +var get = (object, path) => { + return path.reduce((current, nextProperty) => current[nextProperty], object); +}; +var set = (object, path, mutator) => { + const lastProperty = path[path.length - 1]; + const parentPath = [...path].slice(0, -1); + const parent = get(object, parentPath); + if (typeof mutator === "function") { + parent[lastProperty] = mutator(parent[lastProperty]); + } else { + parent[lastProperty] = mutator; + } +}; + +// pkg/dist-src/extract-page-info.js +var extractPageInfos = (responseData) => { + const pageInfoPath = findPaginatedResourcePath(responseData); + return { + pathInQuery: pageInfoPath, + pageInfo: get(responseData, [...pageInfoPath, "pageInfo"]) + }; +}; + +// pkg/dist-src/iterator.js +var import_core = __nccwpck_require__(6762); + +// pkg/dist-src/page-info.js +var isForwardSearch = (givenPageInfo) => { + return givenPageInfo.hasOwnProperty("hasNextPage"); +}; +var getCursorFrom = (pageInfo) => isForwardSearch(pageInfo) ? pageInfo.endCursor : pageInfo.startCursor; +var hasAnotherPage = (pageInfo) => isForwardSearch(pageInfo) ? pageInfo.hasNextPage : pageInfo.hasPreviousPage; + +// pkg/dist-src/iterator.js +var createIterator = (octokit) => { + return (query, initialParameters = {}) => { + let nextPageExists = true; + let parameters = { ...initialParameters }; + return { + [Symbol.asyncIterator]: () => ({ + async next() { + if (!nextPageExists) + return { done: true, value: {} }; + const response = await octokit.graphql( + query, + parameters + ); + const pageInfoContext = extractPageInfos(response); + const nextCursorValue = getCursorFrom(pageInfoContext.pageInfo); + nextPageExists = hasAnotherPage(pageInfoContext.pageInfo); + if (nextPageExists && nextCursorValue === parameters.cursor) { + throw new MissingCursorChange(pageInfoContext, nextCursorValue); + } + parameters = { + ...parameters, + cursor: nextCursorValue + }; + return { done: false, value: response }; + } + }) + }; + }; +}; + +// pkg/dist-src/paginate.js +var import_core2 = __nccwpck_require__(6762); + +// pkg/dist-src/merge-responses.js +var mergeResponses = (response1, response2) => { + if (Object.keys(response1).length === 0) { + return Object.assign(response1, response2); + } + const path = findPaginatedResourcePath(response1); + const nodesPath = [...path, "nodes"]; + const newNodes = get(response2, nodesPath); + if (newNodes) { + set(response1, nodesPath, (values) => { + return [...values, ...newNodes]; + }); + } + const edgesPath = [...path, "edges"]; + const newEdges = get(response2, edgesPath); + if (newEdges) { + set(response1, edgesPath, (values) => { + return [...values, ...newEdges]; + }); + } + const pageInfoPath = [...path, "pageInfo"]; + set(response1, pageInfoPath, get(response2, pageInfoPath)); + return response1; +}; + +// pkg/dist-src/paginate.js +var createPaginate = (octokit) => { + const iterator = createIterator(octokit); + return async (query, initialParameters = {}) => { + let mergedResponse = {}; + for await (const response of iterator( + query, + initialParameters + )) { + mergedResponse = mergeResponses(mergedResponse, response); + } + return mergedResponse; + }; +}; + +// pkg/dist-src/index.js +function paginateGraphql(octokit) { + octokit.graphql; + return { + graphql: Object.assign(octokit.graphql, { + paginate: Object.assign(createPaginate(octokit), { + iterator: createIterator(octokit) + }) + }) + }; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (0); + + /***/ }), /***/ 4193: @@ -35281,14 +35500,27 @@ __nccwpck_require__.r(__webpack_exports__); var core = __nccwpck_require__(2186); // EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js var github = __nccwpck_require__(5438); +// EXTERNAL MODULE: ./node_modules/@octokit/plugin-paginate-graphql/dist-node/index.js +var dist_node = __nccwpck_require__(5883); +// EXTERNAL MODULE: ./node_modules/@actions/github/lib/utils.js +var utils = __nccwpck_require__(3030); ;// CONCATENATED MODULE: ./src/github.js + class GitHub { constructor() { const token = core.getInput("token") || process.env.GITHUB_TOKEN || ""; - this.octokit = github.getOctokit(token); + // Exit early if no token is provided. + if (token.length === 0) { + core.error("No GitHub token provided."); + } + + // Create a new Octokit class instance with the paginateGraphql plugin. + this.octokitInstance = utils.GitHub.plugin(dist_node.paginateGraphql); + // Instantiate the Octokit class with the paginateGraphql plugin. + this.octokit = this.octokitInstance((0,utils.getOctokitOptions)(token)); } /** @@ -35318,8 +35550,12 @@ class GitHub { async getContributorData({ owner, repo, prNumber }) { core.info('Gathering contributor list.'); - const data = await this.octokit.graphql( - `query($owner:String!, $name:String!, $prNumber:Int!) { + const ownerTest = 'WordPress'; + const repoTest = 'gutenberg'; + const prNumberTest = 57841; + + const data = await this.octokit.graphql.paginateGraphql( + `query($owner:String!, $name:String!, $prNumber:Int!, $cursor: String) { repository(owner:$owner, name:$name) { pullRequest(number:$prNumber) { commits(first: 100) { @@ -35351,6 +35587,10 @@ class GitHub { login } } + pageInfo { + hasNextPage + endCursor + } } closingIssuesReferences(first:100){ nodes { @@ -35369,7 +35609,7 @@ class GitHub { } } }`, - { owner, name: repo, prNumber } + { ownerTest, name: repoTest, prNumberTest } ); return data?.repository?.pullRequest; diff --git a/src/github.js b/src/github.js index 6f63612..6e94df5 100644 --- a/src/github.js +++ b/src/github.js @@ -43,6 +43,10 @@ export default class GitHub { async getContributorData({ owner, repo, prNumber }) { core.info('Gathering contributor list.'); + const ownerTest = 'WordPress'; + const repoTest = 'gutenberg'; + const prNumberTest = 57841; + const data = await this.octokit.graphql.paginateGraphql( `query($owner:String!, $name:String!, $prNumber:Int!, $cursor: String) { repository(owner:$owner, name:$name) { @@ -98,7 +102,7 @@ export default class GitHub { } } }`, - { owner, name: repo, prNumber } + { ownerTest, name: repoTest, prNumberTest } ); return data?.repository?.pullRequest;