From 7cde776801771a9b28fa08d7ed83d14fa61f24f7 Mon Sep 17 00:00:00 2001 From: Olabode Lawal-Shittabey Date: Wed, 6 Nov 2024 19:19:59 +0100 Subject: [PATCH] fix(success): PRs not recognized as resolved issues (#960) * feat(success): enhance `buildRelatedIssuesQuery` to include additional fields for `PullRequest` * feat(success): refactor `buildIssuesOrPRsFromResponseNode` to remove `type` parameter and include `__typename` in queries to use in its place * update doc * fix(success): correct `buildRelatedIssuesQuery` to use `issueOrPullRequest` for improved query flexibility * feat(tests): add `__typename` field to issues and pull requests in success tests for improved type handling * feat(tests): update test data to include `__typename` for PullRequest in integration tests --------- Co-authored-by: Gregor Martynus <39992+gr2m@users.noreply.github.com> --- lib/success.js | 31 ++++++++++++---- test/integration.test.js | 2 +- test/success.test.js | 80 ++++++++++++++++++++++++---------------- 3 files changed, 73 insertions(+), 40 deletions(-) diff --git a/lib/success.js b/lib/success.js index 4e3e2b71..5363863c 100644 --- a/lib/success.js +++ b/lib/success.js @@ -88,7 +88,7 @@ export default async function success(pluginConfig, context, { Octokit }) { for (const { nodes, pageInfo } of responseAssociatedPRs) { if (nodes.length === 0) continue; - responsePRs.push(...buildIssuesOrPRsFromResponseNode(nodes, "PR")); + responsePRs.push(...buildIssuesOrPRsFromResponseNode(nodes)); if (pageInfo.hasNextPage) { let cursor = pageInfo.endCursor; let hasNextPage = true; @@ -171,7 +171,7 @@ export default async function success(pluginConfig, context, { Octokit }) { if (!isEmpty(parsedIssues)) { const uniqueParsedIssues = uniqBy(flatten(parsedIssues), "number"); - // Get relatedIssues + // Get relatedIssues (or relatedPRs i.e. Issues/PRs that are closed by an associatedPR) issues = await inChunks(uniqueParsedIssues, 100, async (chunk) => { const { repository } = await octokit.graphql( buildRelatedIssuesQuery(chunk.map((issue) => issue.number)), @@ -360,6 +360,7 @@ async function inChunks(items, chunkSize, callback) { * Fields common accross PRs and Issue */ const baseFields = ` + __typename id title body @@ -420,8 +421,25 @@ function buildRelatedIssuesQuery(numbers) { repository(owner: $owner, name: $repo) { ${numbers .map((num) => { - return `issue${num}: issue(number: ${num}) { - ${baseFields} + return `issue${num}: issueOrPullRequest(number: ${num}) { + ... on Issue { + ${baseFields} + } + ... on PullRequest { + ${baseFields} + mergeable + changedFiles + mergedAt + isDraft + mergedBy { + login + avatarUrl + url + } + commits { + totalCount + } + } }`; }) .join("")} @@ -513,10 +531,9 @@ const loadSingleCommitAssociatedPRs = `#graphql /** * Build associatedPRs or RelatedIssues object (into issue-like object with `pull_request` property) from the GraphQL repository response * @param {object} responseNodes - * @param {"ISSUE" | "PR"} type * @returns {object[]} */ -function buildIssuesOrPRsFromResponseNode(responseNodes, type = "ISSUE") { +function buildIssuesOrPRsFromResponseNode(responseNodes) { const resultArray = []; for (const node of responseNodes) { let baseProps = { @@ -569,7 +586,7 @@ function buildIssuesOrPRsFromResponseNode(responseNodes, type = "ISSUE") { let result = baseProps; - if (type === "PR") { + if (node.__typename === "PullRequest") { const prProps = { pull_request: true, mergeable: node.mergeable, diff --git a/test/integration.test.js b/test/integration.test.js index 872aa08b..ffcae3ed 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -433,7 +433,7 @@ test("Comment and add labels on PR included in the releases", async (t) => { const repo = "test_repo"; const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; diff --git a/test/success.test.js b/test/success.test.js index b34494e5..6f8a4ed5 100644 --- a/test/success.test.js +++ b/test/success.test.js @@ -33,8 +33,8 @@ test("Add comment and labels to PRs associated with release commits and issues s const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, body: "Fixes #3", state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", body: "Fixes #3", state: "closed" }, ]; const options = { branch: "master", @@ -103,6 +103,7 @@ test("Add comment and labels to PRs associated with release commits and issues s data: { repository: { issue3: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -139,6 +140,7 @@ test("Add comment and labels to PRs associated with release commits and issues s locked: false, }, issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -317,10 +319,10 @@ test("Add comment and labels to PRs associated with release commits and issues ( const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, body: "Fixes #3", state: "closed" }, - { number: 5, pull_request: true, state: "closed" }, - { number: 6, pull_request: true, state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", body: "Fixes #3", state: "closed" }, + { number: 5, __typename: "PullRequest", state: "closed" }, + { number: 6, __typename: "PullRequest", state: "closed" }, ]; const options = { branch: "master", @@ -414,6 +416,7 @@ test("Add comment and labels to PRs associated with release commits and issues ( data: { repository: { issue3: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -450,6 +453,7 @@ test("Add comment and labels to PRs associated with release commits and issues ( locked: false, }, issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -607,8 +611,8 @@ test("Add comment and labels to PRs associated with release commits and issues c const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, body: "Fixes #3", state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", body: "Fixes #3", state: "closed" }, ]; const options = { branch: "master", @@ -671,6 +675,7 @@ test("Add comment and labels to PRs associated with release commits and issues c data: { repository: { issue3: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -707,6 +712,7 @@ test("Add comment and labels to PRs associated with release commits and issues c locked: false, }, issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -905,12 +911,12 @@ test("Make multiple search queries if necessary", async (t) => { const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, state: "closed" }, - { number: 3, pull_request: true, state: "closed" }, - { number: 4, pull_request: true, state: "closed" }, - { number: 5, pull_request: true, state: "closed" }, - { number: 6, pull_request: true, state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", state: "closed" }, + { number: 3, __typename: "PullRequest", state: "closed" }, + { number: 4, __typename: "PullRequest", state: "closed" }, + { number: 5, __typename: "PullRequest", state: "closed" }, + { number: 6, __typename: "PullRequest", state: "closed" }, ]; const options = { branch: "master", @@ -1210,8 +1216,8 @@ test("Do not add comment and labels for unrelated PR returned by search (compare const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", state: "closed" }, ]; const options = { branch: "master", @@ -1677,9 +1683,9 @@ test("Ignore missing and forbidden issues/PRs", async (t) => { const failTitle = "The automated release is failing 🚨"; const pluginConfig = { failTitle }; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, body: "Fixes #4", state: "closed" }, - { number: 3, pull_request: true, body: "Fixes #5", state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", body: "Fixes #4", state: "closed" }, + { number: 3, __typename: "PullRequest", body: "Fixes #5", state: "closed" }, ]; const options = { branch: "master", @@ -1750,6 +1756,7 @@ test("Ignore missing and forbidden issues/PRs", async (t) => { data: { repository: { issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -1786,6 +1793,7 @@ test("Ignore missing and forbidden issues/PRs", async (t) => { locked: false, }, issue5: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -1822,6 +1830,7 @@ test("Ignore missing and forbidden issues/PRs", async (t) => { locked: false, }, issue1: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -2008,7 +2017,7 @@ test("Add custom comment and labels", async (t) => { ], }; const prs = [ - { number: 1, prop: "PR prop", pull_request: true, state: "closed" }, + { number: 1, prop: "PR prop", __typename: "PullRequest", state: "closed" }, ]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` }; const lastRelease = { version: "1.0.0" }; @@ -2129,7 +2138,7 @@ test("Add custom label", async (t) => { const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: ["custom label"], failTitle }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` }; const lastRelease = { version: "1.0.0" }; const commits = [{ hash: "123", message: "Commit 1 message" }]; @@ -2242,7 +2251,7 @@ test("Comment on issue/PR without ading a label", async (t) => { const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, failTitle }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` }; const lastRelease = { version: "1.0.0" }; const commits = [{ hash: "123", message: "Commit 1 message" }]; @@ -2347,7 +2356,7 @@ test("Editing the release to include all release links at the bottom", async (t) const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "bottom" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; @@ -2478,7 +2487,7 @@ test("Editing the release to include all release links at the top", async (t) => const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "top" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; @@ -2609,7 +2618,7 @@ test("Editing the release to include all release links with no additional releas const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "top" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; @@ -2726,7 +2735,7 @@ test("Editing the release to include all release links with no additional releas const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "bottom" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; @@ -2843,7 +2852,7 @@ test("Editing the release to include all release links with no releases", async const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "bottom" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, }; @@ -2953,7 +2962,7 @@ test("Editing the release with no ID in the release", async (t) => { const env = { GITHUB_TOKEN: "github_token" }; const failTitle = "The automated release is failing 🚨"; const pluginConfig = { releasedLabels: false, addReleases: "bottom" }; - const prs = [{ number: 1, pull_request: true, state: "closed" }]; + const prs = [{ number: 1, __typename: "PullRequest", state: "closed" }]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git` }; const nextRelease = { version: "2.0.0", @@ -3071,8 +3080,8 @@ test("Ignore errors when adding comments and closing issues", async (t) => { { number: 3, body: `Issue 3 body\n\n${ISSUE_ID}`, title: failTitle }, ]; const prs = [ - { number: 1, pull_request: true, state: "closed" }, - { number: 2, pull_request: true, state: "closed" }, + { number: 1, __typename: "PullRequest", state: "closed" }, + { number: 2, __typename: "PullRequest", state: "closed" }, ]; const options = { repositoryUrl: `https://github.com/${owner}/${repo}.git`, @@ -3524,6 +3533,7 @@ test('Add comment and label to found issues/associatedPR using the "successComme const prs = [ { + __typename: "PullRequest", id: "PR_kwDOMLlZj85z_R2M", title: "fix: will semantic-release recognize the associated issue ", body: "", @@ -3574,6 +3584,7 @@ test('Add comment and label to found issues/associatedPR using the "successComme }, }, { + __typename: "PullRequest", id: "PR_kwDOMLlZj85z_R2M", title: "fix: will semantic-release recognize the associated issue ", body: "", @@ -3775,6 +3786,7 @@ test('Does not comment/label associatedPR and relatedIssues created by "Bots"', ]; const prs = [ { + __typename: "PullRequest", number: 2, id: "PR_kwDOMLlZj851SZzc", title: "pr title", @@ -3823,6 +3835,7 @@ test('Does not comment/label associatedPR and relatedIssues created by "Bots"', }, }, { + __typename: "PullRequest", number: 3, id: "PR_kwDOMLlZj851SZzc", title: "pr title", @@ -3916,6 +3929,7 @@ test('Does not comment/label associatedPR and relatedIssues created by "Bots"', data: { repository: { issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -3952,6 +3966,7 @@ test('Does not comment/label associatedPR and relatedIssues created by "Bots"', locked: false, }, issue5: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "", @@ -4120,8 +4135,8 @@ test('Does not comment/label "associatedPR" when "successCommentCondition" disab }, ]; const prs = [ - { number: 2, pull_request: true, body: "Fixes #4", state: "closed" }, - { number: 3, pull_request: true, state: "closed" }, + { number: 2, __typename: "PullRequest", body: "Fixes #4", state: "closed" }, + { number: 3, __typename: "PullRequest", state: "closed" }, ]; const fetch = fetchMock @@ -4168,6 +4183,7 @@ test('Does not comment/label "associatedPR" when "successCommentCondition" disab data: { repository: { issue4: { + __typename: "Issue", id: "I_kw", title: "issue title", body: "",