semantic-release / github

:octocat: semantic-release plugin to publish a GitHub release and comment on released Pull Requests/Issues
https://www.npmjs.com/package/@semantic-release/github
MIT License
407 stars 125 forks source link

fix(edge-case): fetching `associatedPRs` on 100+ `context.commits` in `success` lifecycle #892

Closed babblebey closed 1 month ago

babblebey commented 2 months ago

This Pull Request addresses the following edge cases in our consumption of GraphQL at fetching associatedPRs for context.commits list in the success lifecycle of the plugin.

1. Fetching associatedPRs for 100+ context.commits

We currently use GraphQL Fragments to query associatedPRs for each commit in the context.commits array, this grants us the ability to get associatedPRs for alot of commits by making just one request. BUT, we are limited to a fragment of only 100 items which means that we can only query associatedPRs for 100 commits in one request, and needing to make another request for the next set of 100 incases where there's more than 100.

THE FIX: Implemented logic to split the context.commits array into chunks of 100 items, which is then consumed by the buildAssociatedPRsQuery utils that builds the GraphQL query fragment, requests the associatedPRs per chunk and ends up merging/consolidating all response nodes from each chunks into on final array of associatedPRs

2. When associatedPRs response nodes is more than 100 (kinda unlikely, but wouldn't hurt to address 🤔)

When associatedPRs are fetched for each commit, there's a possibility that the response items is more than 100 🫣. Important to note that "Maximum response nodes is 100 items with the rest paginated" this means we can only get back 100 nodes and the rest split to another page of 100 max nodes.

THE FIX: Implemented a second graphQL query loadSingleCommitAssociatedPRs (seen below) which is used to fetch the next page in a paginated response for individual associatedPRs. This is made possible with the pageInfo value in the response object, which triggers a call to this query if initial response hasNextPage is true and uses the endCursor value as the starting point for next response nodes to fetch.

const loadSingleCommitAssociatedPRs = `#graphql
  query getCommitAssociatedPRs($owner: String!, $repo: String!, $sha: String!, $cursor: String) {
    repository(owner: $owner, name: $repo) {
      commit: object(oid: $sha) {
        ...on Commit {
          associatedPullRequests(after: $cursor, first: 1) {
            pageInfo {
              endCursor
              hasNextPage
            }
            nodes {
              url
              number
              body
            }
          }
        }
      }
    }
  }
`;

Important to state that this logic is consumed inside each context.commits chunks to consolidate the paginated associatedPRs response node in the final associatedPRs array.

Related Issue

Fixes #868

Screencast/Screenshot

Demo (Setting chunk-size and graphql query page request size property first to 1)

https://github.com/user-attachments/assets/0a7f32d4-cbab-4379-a805-d521ade6f294

github-actions[bot] commented 1 month ago

:tada: This issue has been resolved in version 10.1.6 :tada:

The release is available on:

Your semantic-release bot :package::rocket: