diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88694f36..b7e55975 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: npm node-version: lts/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 576099a7..f83deac3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: "Use Node.js ${{ matrix.node-version }}" - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version: "${{ matrix.node-version }}" cache: npm @@ -46,7 +46,7 @@ jobs: - run: git config --global user.name github-actions - run: git config --global user.email github-actions@github.com - name: Use Node.js from .nvmrc - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version-file: .nvmrc cache: npm diff --git a/lib/definitions/constants.js b/lib/definitions/constants.js index dc22169a..c0400947 100644 --- a/lib/definitions/constants.js +++ b/lib/definitions/constants.js @@ -1,3 +1,5 @@ export const ISSUE_ID = ""; export const RELEASE_NAME = "GitHub release"; + +export const RELEASE_FAIL_LABEL = "semantic-release"; diff --git a/lib/fail.js b/lib/fail.js index 070b076e..723b0510 100644 --- a/lib/fail.js +++ b/lib/fail.js @@ -2,7 +2,7 @@ import { template } from "lodash-es"; import debugFactory from "debug"; import parseGithubUrl from "./parse-github-url.js"; -import { ISSUE_ID } from "./definitions/constants.js"; +import { ISSUE_ID, RELEASE_FAIL_LABEL } from "./definitions/constants.js"; import resolveConfig from "./resolve-config.js"; import { toOctokitOptions } from "./octokit.js"; import findSRIssues from "./find-sr-issues.js"; @@ -57,7 +57,14 @@ export default async function fail(pluginConfig, context, { Octokit }) { const body = failComment ? template(failComment)({ branch, errors }) : getFailComment(branch, errors); - const [srIssue] = await findSRIssues(octokit, failTitle, owner, repo); + const [srIssue] = await findSRIssues( + octokit, + logger, + failTitle, + labels, + owner, + repo, + ); const canCommentOnOrCreateIssue = failCommentCondition ? template(failCommentCondition)({ ...context, issue: srIssue }) @@ -85,7 +92,7 @@ export default async function fail(pluginConfig, context, { Octokit }) { repo, title: failTitle, body: `${body}\n\n${ISSUE_ID}`, - labels: labels || [], + labels: (labels || []).concat([RELEASE_FAIL_LABEL]), assignees, }; debug("create issue: %O", newIssue); diff --git a/lib/find-sr-issues.js b/lib/find-sr-issues.js index d0fe8760..47af4104 100644 --- a/lib/find-sr-issues.js +++ b/lib/find-sr-issues.js @@ -1,11 +1,63 @@ -import { ISSUE_ID } from "./definitions/constants.js"; +import { uniqBy } from "lodash-es"; +import { ISSUE_ID, RELEASE_FAIL_LABEL } from "./definitions/constants.js"; + +export default async (octokit, logger, title, labels, owner, repo) => { + let issues = []; -export default async (octokit, title, owner, repo) => { const { - data: { items: issues }, - } = await octokit.request("GET /search/issues", { - q: `in:title+repo:${owner}/${repo}+type:issue+state:open+${title}`, + repository: { + issues: { nodes: issueNodes }, + }, + } = await octokit.graphql(loadGetSRIssuesQuery, { + owner, + repo, + filter: { + labels: (labels || []).concat([RELEASE_FAIL_LABEL]), + }, }); - return issues.filter((issue) => issue.body && issue.body.includes(ISSUE_ID)); + issues.push(...issueNodes); + + /** + * BACKWARD COMPATIBILITY: Fallback to the search API if the issue was not found in the GraphQL response. + * This fallback will be removed in a future release + */ + if (issueNodes.length === 0) { + try { + const { + data: { items: backwardIssues }, + } = await octokit.request("GET /search/issues", { + q: `in:title+repo:${owner}/${repo}+type:issue+state:open+${title}`, + }); + issues.push(...backwardIssues); + } catch (error) { + logger.log( + "An error occured fetching issue via fallback (with GH SearchAPI)", + ); + } + } + + const uniqueSRIssues = uniqBy( + issues.filter((issue) => issue.body && issue.body.includes(ISSUE_ID)), + "number", + ); + + return uniqueSRIssues; }; + +/** + * GraphQL Query to et the semantic-release issues for a repository. + */ +const loadGetSRIssuesQuery = `#graphql + query getSRIssues($owner: String!, $repo: String!, $filter: IssueFilters) { + repository(owner: $owner, name: $repo) { + issues(first: 100, states: OPEN, filterBy: $filter) { + nodes { + number + title + body + } + } + } + } +`; diff --git a/lib/success.js b/lib/success.js index 06fe203c..705f02aa 100644 --- a/lib/success.js +++ b/lib/success.js @@ -28,6 +28,7 @@ export default async function success(pluginConfig, context, { Octokit }) { githubApiPathPrefix, githubApiUrl, proxy, + labels, successComment, successCommentCondition, failTitle, @@ -266,7 +267,14 @@ export default async function success(pluginConfig, context, { Octokit }) { if (failComment === false || failTitle === false) { logger.log("Skip closing issue."); } else { - const srIssues = await findSRIssues(octokit, failTitle, owner, repo); + const srIssues = await findSRIssues( + octokit, + logger, + failTitle, + labels, + owner, + repo, + ); debug("found semantic-release issues: %O", srIssues); diff --git a/package-lock.json b/package-lock.json index 0021266e..18158a6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "ls-engines": "0.9.3", "npm-run-all2": "6.2.3", "prettier": "3.3.3", - "publint": "0.2.10", + "publint": "0.2.11", "semantic-release": "24.1.1", "sinon": "19.0.2", "tempy": "3.1.0" @@ -435,14 +435,14 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "19.0.3", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz", - "integrity": "sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.5.0.tgz", + "integrity": "sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@commitlint/types": "^19.0.3", + "@commitlint/types": "^19.5.0", "ajv": "^8.11.0" }, "engines": { @@ -450,9 +450,9 @@ } }, "node_modules/@commitlint/execute-rule": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", - "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz", + "integrity": "sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==", "dev": true, "license": "MIT", "optional": true, @@ -461,17 +461,17 @@ } }, "node_modules/@commitlint/load": { - "version": "19.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.4.0.tgz", - "integrity": "sha512-I4lCWaEZYQJ1y+Y+gdvbGAx9pYPavqZAZ3/7/8BpWh+QjscAn8AjsUpLV2PycBsEx7gupq5gM4BViV9xwTIJuw==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.5.0.tgz", + "integrity": "sha512-INOUhkL/qaKqwcTUvCE8iIUf5XHsEPCLY9looJ/ipzi7jtGhgmtH7OOFiNvwYgH7mA8osUWOUDV8t4E2HAi4xA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@commitlint/config-validator": "^19.0.3", - "@commitlint/execute-rule": "^19.0.0", - "@commitlint/resolve-extends": "^19.1.0", - "@commitlint/types": "^19.0.3", + "@commitlint/config-validator": "^19.5.0", + "@commitlint/execute-rule": "^19.5.0", + "@commitlint/resolve-extends": "^19.5.0", + "@commitlint/types": "^19.5.0", "chalk": "^5.3.0", "cosmiconfig": "^9.0.0", "cosmiconfig-typescript-loader": "^5.0.0", @@ -484,15 +484,15 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz", - "integrity": "sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz", + "integrity": "sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@commitlint/config-validator": "^19.0.3", - "@commitlint/types": "^19.0.3", + "@commitlint/config-validator": "^19.5.0", + "@commitlint/types": "^19.5.0", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", @@ -503,9 +503,9 @@ } }, "node_modules/@commitlint/types": { - "version": "19.0.3", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz", - "integrity": "sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.5.0.tgz", + "integrity": "sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==", "dev": true, "license": "MIT", "optional": true, @@ -1540,9 +1540,9 @@ } }, "node_modules/@semantic-release/github": { - "version": "10.3.3", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.3.3.tgz", - "integrity": "sha512-zrEdwRZ7ZTEM2JYhF4E+ZgApIfv6iHfQBnnAP1g2LqYZtj56+qWEUo/xW36cbZRDOweejxU40PGZckx6TZzFmg==", + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.3.4.tgz", + "integrity": "sha512-JghCkEk7e2u+iauMje8lgHH11pbtaz9yTdMn/PyfulCdBshIwpp+Mu/NR8Ml216auEUtvmBpQX5+Cth2TsVUVw==", "dev": true, "license": "MIT", "dependencies": { @@ -1973,9 +1973,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.5.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "dev": true, "license": "MIT", "optional": true, @@ -2100,9 +2100,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -2187,9 +2187,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -2900,9 +2900,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001658", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001658.tgz", - "integrity": "sha512-N2YVqWbJELVdrnsW5p+apoQyYt51aBMSsBZki1XZEfeBCexcM/sf4xiAHcXQBkuOwJBXtWF7aW1sYX6tKebPHw==", + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", "dev": true, "funding": [ { @@ -4192,9 +4192,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.18", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", - "integrity": "sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==", + "version": "1.5.23", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.23.tgz", + "integrity": "sha512-mBhODedOXg4v5QWwl21DjM5amzjmI1zw9EPrPK/5Wx7C8jt33bpZNrC7OhHUG3pxRtbLpr3W2dXT+Ph1SsfRZA==", "dev": true, "license": "ISC" }, @@ -6565,9 +6565,9 @@ } }, "node_modules/is-unicode-supported": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", - "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { @@ -12323,14 +12323,14 @@ "license": "ISC" }, "node_modules/publint": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/publint/-/publint-0.2.10.tgz", - "integrity": "sha512-5TzYaAFiGpgkYX/k6VaItRMT2uHI4zO5OWJ2k7Er0Ot3jutBCNTJB1qRHuy1lYq07JhRczzFs6HFPB4D+A47xA==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/publint/-/publint-0.2.11.tgz", + "integrity": "sha512-/kxbd+sD/uEG515N/ZYpC6gYs8h89cQ4UIsAq1y6VT4qlNh8xmiSwcP2xU2MbzXFl8J0l2IdONKFweLfYoqhcA==", "dev": true, "license": "MIT", "dependencies": { "npm-packlist": "^5.1.3", - "picocolors": "^1.0.1", + "picocolors": "^1.1.0", "sade": "^1.8.1" }, "bin": { @@ -14788,9 +14788,9 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, "license": "Apache-2.0", "optional": true, diff --git a/package.json b/package.json index 6cabc33b..720b46ae 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "ls-engines": "0.9.3", "npm-run-all2": "6.2.3", "prettier": "3.3.3", - "publint": "0.2.10", + "publint": "0.2.11", "semantic-release": "24.1.1", "sinon": "19.0.2", "tempy": "3.1.0" diff --git a/test/fail.test.js b/test/fail.test.js index f0277d8d..37ceb6bd 100644 --- a/test/fail.test.js +++ b/test/fail.test.js @@ -3,7 +3,7 @@ import sinon from "sinon"; import test from "ava"; import fetchMock from "fetch-mock"; -import { ISSUE_ID } from "../lib/definitions/constants.js"; +import { ISSUE_ID, RELEASE_FAIL_LABEL } from "../lib/definitions/constants.js"; import { TestOctokit } from "./helpers/test-octokit.js"; /* eslint camelcase: ["error", {properties: "never"}] */ @@ -36,6 +36,13 @@ test("Open a new issue with the list of errors", async (t) => { .getOnce("https://api.github.local/repos/test_user/test_repo", { full_name: `${redirectedOwner}/${redirectedRepo}`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -59,7 +66,7 @@ test("Open a new issue with the list of errors", async (t) => { data.body, /---\n\n### Error message 1\n\nError 1 details\n\n---\n\n### Error message 2\n\nError 2 details\n\n---\n\n### Error message 3\n\nError 3 details\n\n---/, ); - t.deepEqual(data.labels, ["semantic-release"]); + t.deepEqual(data.labels, ["semantic-release", RELEASE_FAIL_LABEL]); return true; }, { @@ -117,6 +124,13 @@ test("Open a new issue with the list of errors and custom title and comment", as full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -132,7 +146,7 @@ test("Open a new issue with the list of errors and custom title and comment", as body: { title: failTitle, body: `branch master Error message 1 Error message 2 Error message 3\n\n${ISSUE_ID}`, - labels: ["semantic-release"], + labels: ["semantic-release", RELEASE_FAIL_LABEL], }, }, ); @@ -185,6 +199,13 @@ test("Open a new issue with assignees and the list of errors", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -203,7 +224,7 @@ test("Open a new issue with assignees and the list of errors", async (t) => { data.body, /---\n\n### Error message 1\n\nError 1 details\n\n---\n\n### Error message 2\n\nError 2 details\n\n---/, ); - t.deepEqual(data.labels, ["semantic-release"]); + t.deepEqual(data.labels, ["semantic-release", RELEASE_FAIL_LABEL]); t.deepEqual(data.assignees, ["user1", "user2"]); return true; }, @@ -258,6 +279,13 @@ test("Open a new issue without labels and the list of errors", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -276,7 +304,7 @@ test("Open a new issue without labels and the list of errors", async (t) => { data.body, /---\n\n### Error message 1\n\nError 1 details\n\n---\n\n### Error message 2\n\nError 2 details\n\n---/, ); - t.deepEqual(data.labels, []); + t.deepEqual(data.labels, [RELEASE_FAIL_LABEL]); return true; }, { html_url: "https://github.com/issues/1", number: 1 }, @@ -335,14 +363,13 @@ test("Update the first existing issue with the list of errors", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .getOnce( - `https://api.github.local/search/issues?q=${encodeURIComponent( - "in:title", - )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( - "type:issue", - )}+${encodeURIComponent("state:open")}+${encodeURIComponent(failTitle)}`, - { items: issues }, - ) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }) .postOnce( (url, { body }) => { t.is( @@ -501,13 +528,17 @@ test('Does not post comments on existing issues when "failCommentCondition" is " .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { full_name: `${owner}/${repo}`, }) - .getOnce( - `https://api.github.local/search/issues?q=${encodeURIComponent( - "in:title", - )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( - "type:issue", - )}+${encodeURIComponent("state:open")}+${encodeURIComponent(failTitle)}`, - { items: issues }, + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getSRIssues("), + { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }, ); await fail( @@ -551,6 +582,18 @@ test(`Post new issue if none exists yet, but don't comment on existing issues wh .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { full_name: `${owner}/${repo}`, }) + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getSRIssues("), + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", diff --git a/test/find-sr-issue.test.js b/test/find-sr-issue.test.js index b6e4cefd..fc10c2f0 100644 --- a/test/find-sr-issue.test.js +++ b/test/find-sr-issue.test.js @@ -17,6 +17,7 @@ test("Filter out issues without ID", async (t) => { const owner = "test_user"; const repo = "test_repo"; const title = "The automated release is failing 🚨"; + const labels = []; const issues = [ { number: 1, body: "Issue 1 body", title }, { number: 2, body: `Issue 2 body\n\n${ISSUE_ID}`, title }, @@ -25,18 +26,19 @@ test("Filter out issues without ID", async (t) => { const fetch = fetchMock .sandbox() - .getOnce( - `https://api.github.local/search/issues?q=${encodeURIComponent( - "in:title", - )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( - "type:issue", - )}+${encodeURIComponent("state:open")}+${encodeURIComponent(title)}`, - { items: issues }, - ); + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }); const srIssues = await findSRIssues( new TestOctokit({ request: { fetch } }), + t.context.logger, title, + labels, owner, repo, ); @@ -61,9 +63,17 @@ test("Return empty array if not issues found", async (t) => { const owner = "test_user"; const repo = "test_repo"; const title = "The automated release is failing 🚨"; + const labels = []; const issues = []; const fetch = fetchMock .sandbox() + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -75,7 +85,9 @@ test("Return empty array if not issues found", async (t) => { const srIssues = await findSRIssues( new TestOctokit({ request: { fetch } }), + t.context.logger, title, + labels, owner, repo, ); @@ -89,28 +101,111 @@ test("Return empty array if not issues has matching ID", async (t) => { const owner = "test_user"; const repo = "test_repo"; const title = "The automated release is failing 🚨"; + const labels = []; const issues = [ { number: 1, body: "Issue 1 body", title }, { number: 2, body: "Issue 2 body", title }, ]; const fetch = fetchMock .sandbox() + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }); + + const srIssues = await findSRIssues( + new TestOctokit({ request: { fetch } }), + t.context.logger, + title, + labels, + owner, + repo, + ); + + t.deepEqual(srIssues, []); + t.true(fetch.done()); +}); + +test("Handle error in searchAPI fallback", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const title = "The automated release is failing 🚨"; + const labels = []; + const issues = []; + + const response = new Response("Not Found", { + url: "https://api.github.com/search/issues?q=in%3Atitle+repo%3Aourorg%2Frepo+type%3Aissue+state%3Aopen+The%20automated%20release%20is%20failing%20%F0%9F%9A%A8", + status: 403, + headers: { + "access-control-allow-origin": "*", + "access-control-expose-headers": + "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset", + "content-encoding": "gzip", + "content-security-policy": "default-repo 'none'", + "content-type": "application/json; charset=utf-8", + date: "Tue, 28 May 2024 19:49:00 GMT", + "referrer-policy": + "origin-when-cross-origin, strict-origin-when-cross-origin", + server: "GitHub.com", + "strict-transport-security": + "max-age=31536000; includeSubdomains; preload", + "transfer-encoding": "chunked", + vary: "Accept-Encoding, Accept, X-Requested-With", + "x-content-type-options": "nosniff", + "x-frame-options": "deny", + "x-github-api-version-selected": "2022-11-28", + "x-github-media-type": "github.v3; format=json", + "x-github-request-id": "2**0:29*****4:3868737:6*****3:6****52C", + "x-ratelimit-limit": "30", + "x-ratelimit-remaining": "30", + "x-ratelimit-reset": "1716925800", + "x-ratelimit-resource": "search", + "x-ratelimit-used": "1", + "x-xss-protection": "0", + }, + data: { + documentation_url: + "https://docs.github.com/free-pro-team@latest/rest/overview/rate-limits-for-the-rest-api#about-secondary-rate-limits", + message: + "You have exceeded a secondary rate limit. Please wait a few minutes before you try again. If you reach out to GitHub Support for help, please include the request ID 2840:295B44:3868737:64A2183:6232352C.", + }, + }); + + const fetch = fetchMock + .sandbox() + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( "type:issue", )}+${encodeURIComponent("state:open")}+${encodeURIComponent(title)}`, - { items: issues }, + response, ); const srIssues = await findSRIssues( new TestOctokit({ request: { fetch } }), + t.context.logger, title, + labels, owner, repo, ); - t.deepEqual(srIssues, []); + t.true( + t.context.log.calledWith( + "An error occured fetching issue via fallback (with GH SearchAPI)", + ), + ); + t.log(t.context.log); t.true(fetch.done()); }); diff --git a/test/integration.test.js b/test/integration.test.js index f512c7fa..91400d35 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -2,6 +2,7 @@ import test from "ava"; import sinon from "sinon"; import SemanticReleaseError from "@semantic-release/error"; import fetchMock from "fetch-mock"; +import { RELEASE_FAIL_LABEL } from "../lib/definitions/constants.js"; import { TestOctokit } from "./helpers/test-octokit.js"; @@ -450,22 +451,29 @@ test("Comment and add labels on PR included in the releases", async (t) => { repeat: 2, }, ) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -491,6 +499,20 @@ test("Comment and add labels on PR included in the releases", async (t) => { body: ["released"], }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -556,6 +578,13 @@ test("Open a new issue with the list of errors", async (t) => { }, { repeat: 2 }, ) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -573,7 +602,7 @@ test("Open a new issue with the list of errors", async (t) => { data.body, /---\n\n### Error message 1\n\nError 1 details\n\n---\n\n### Error message 2\n\nError 2 details\n\n---\n\n### Error message 3\n\nError 3 details\n\n---/, ); - t.deepEqual(data.labels, ["semantic-release"]); + t.deepEqual(data.labels, ["semantic-release", RELEASE_FAIL_LABEL]); return true; }, @@ -653,6 +682,39 @@ test("Verify, release and notify success", async (t) => { repeat: 2, }, ) + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getAssociatedPRs("), + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], + }, + }, + }, + }, + }, + ) + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getSRIssues("), + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .postOnce( `https://api.github.local/repos/${owner}/${repo}/releases`, { @@ -675,22 +737,6 @@ test("Verify, release and notify success", async (t) => { { html_url: releaseUrl }, { body: { draft: false } }, ) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, - }, - nodes: [prs[0]], - }, - }, - }, - }, - }) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -834,22 +880,29 @@ test("Verify, update release and notify success", async (t) => { }, }, ) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -867,6 +920,20 @@ test("Verify, update release and notify success", async (t) => { body: ["released"], }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -957,6 +1024,13 @@ test("Verify and notify failure", async (t) => { repeat: 2, }, ) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", diff --git a/test/success.test.js b/test/success.test.js index 36d88c81..29f0c892 100644 --- a/test/success.test.js +++ b/test/success.test.js @@ -215,6 +215,20 @@ test("Add comment and labels to PRs associated with release commits and issues s {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -493,6 +507,20 @@ test("Add comment and labels to PRs associated with release commits and issues ( {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -753,6 +781,20 @@ test("Add comment and labels to PRs associated with release commits and issues c {}, { body: ["released on @next"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://custom-url.com/prefix/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://custom-url.com/prefix/search/issues?q=${encodeURIComponent( "in:title", @@ -877,72 +919,79 @@ test("Make multiple search queries if necessary", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .post("https://api.github.local/graphql", { - data: { - repository: { - commitaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: { - oid: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commitaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: { + oid: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, - }, - commitbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: { - oid: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commitbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: { + oid: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[1]], }, - nodes: [prs[1]], }, - }, - commitcccccccccccccccccccccccccccccccccccccccccc: { - oid: "cccccccccccccccccccccccccccccccccccccccccc", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commitcccccccccccccccccccccccccccccccccccccccccc: { + oid: "cccccccccccccccccccccccccccccccccccccccccc", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[2]], }, - nodes: [prs[2]], }, - }, - commiteeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee: { - oid: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commiteeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee: { + oid: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[3]], }, - nodes: [prs[3]], }, - }, - commitffffffffffffffffffffffffffffffffffffffffff: { - oid: "ffffffffffffffffffffffffffffffffffffffffff", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commitffffffffffffffffffffffffffffffffffffffffff: { + oid: "ffffffffffffffffffffffffffffffffffffffffff", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[4]], }, - nodes: [prs[4]], }, - }, - commitgggggggggggggggggggggggggggggggggggggggggg: { - oid: "gggggggggggggggggggggggggggggggggggggggggg", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commitgggggggggggggggggggggggggggggggggggggggggg: { + oid: "gggggggggggggggggggggggggggggggggggggggggg", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[5]], }, - nodes: [prs[5]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -1033,6 +1082,20 @@ test("Make multiple search queries if necessary", async (t) => { body: ["released"], }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1152,32 +1215,39 @@ test("Do not add comment and labels for unrelated PR returned by search (compare full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, - }, - commit456: { - oid: "456", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commit456: { + oid: "456", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[1]], }, - nodes: [prs[1]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: "rebased_sha" }], @@ -1203,6 +1273,20 @@ test("Do not add comment and labels for unrelated PR returned by search (compare {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1265,22 +1349,43 @@ test("Do not add comment and labels if no PR is associated with release commits" full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [], }, - nodes: [], }, }, }, }, - }) + ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1333,6 +1438,13 @@ test("Do not add comment and labels if no commits is found for release", async ( full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1485,6 +1597,20 @@ test("Do not add comment and labels to PR/issues from other repo", async (t) => {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1757,6 +1883,20 @@ test("Ignore missing and forbidden issues/PRs", async (t) => { {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1859,22 +1999,29 @@ test("Add custom comment and labels", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -1891,6 +2038,20 @@ test("Add custom comment and labels", async (t) => { {}, { body: ["released on @next", "released from master"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -1958,22 +2119,29 @@ test("Add custom label", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -1987,6 +2155,20 @@ test("Add custom label", async (t) => { {}, { body: ["custom label"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2050,22 +2232,29 @@ test("Comment on issue/PR without ading a label", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2074,6 +2263,20 @@ test("Comment on issue/PR without ading a label", async (t) => { `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2149,22 +2352,29 @@ test("Editing the release to include all release links at the bottom", async (t) full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2173,6 +2383,20 @@ test("Editing the release to include all release links at the bottom", async (t) `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2259,22 +2483,29 @@ test("Editing the release to include all release links at the top", async (t) => full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2283,6 +2514,20 @@ test("Editing the release to include all release links at the top", async (t) => `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2366,22 +2611,29 @@ test("Editing the release to include all release links with no additional releas full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2390,6 +2642,20 @@ test("Editing the release to include all release links with no additional releas `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2462,22 +2728,29 @@ test("Editing the release to include all release links with no additional releas full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2486,6 +2759,20 @@ test("Editing the release to include all release links with no additional releas `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2551,22 +2838,29 @@ test("Editing the release to include all release links with no releases", async full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2575,6 +2869,20 @@ test("Editing the release to include all release links with no releases", async `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2642,22 +2950,29 @@ test("Editing the release with no ID in the release", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2666,6 +2981,20 @@ test("Editing the release with no ID in the release", async (t) => { `https://api.github.local/repos/${owner}/${repo}/issues/1/comments`, { html_url: "https://github.com/successcomment-1" }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2738,32 +3067,39 @@ test("Ignore errors when adding comments and closing issues", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[0]], }, - nodes: [prs[0]], }, - }, - commit456: { - oid: "456", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + commit456: { + oid: "456", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [prs[1]], }, - nodes: [prs[1]], }, }, }, }, - }) + ) .getOnce( `https://api.github.local/repos/${owner}/${repo}/pulls/1/commits`, [{ sha: commits[0].hash }], @@ -2785,6 +3121,20 @@ test("Ignore errors when adding comments and closing issues", async (t) => { {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -2885,29 +3235,42 @@ test("Close open issues when a release is successful", async (t) => { full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) - .postOnce("https://api.github.local/graphql", { - data: { - repository: { - commit123: { - oid: "123", - associatedPullRequests: { - pageInfo: { - endCursor: "NI", - hasNextPage: false, + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getAssociatedPRs\(/); + return true; + }, + { + data: { + repository: { + commit123: { + oid: "123", + associatedPullRequests: { + pageInfo: { + endCursor: "NI", + hasNextPage: false, + }, + nodes: [], }, - nodes: [], }, }, }, }, - }) - .getOnce( - `https://api.github.local/search/issues?q=${encodeURIComponent( - "in:title", - )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( - "type:issue", - )}+${encodeURIComponent("state:open")}+${encodeURIComponent(failTitle)}`, - { items: issues }, + ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }, ) .patchOnce( `https://api.github.local/repos/${owner}/${repo}/issues/2`, @@ -2991,6 +3354,20 @@ test('Skip comment on on issues/PR if "successComment" is "false"', async (t) => full_name: `${owner}/${repo}`, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -3051,6 +3428,13 @@ test('Does not comment/label on issues/PR if "successCommentCondition" is "false .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { full_name: `${owner}/${repo}`, }) + .postOnce("https://api.github.local/graphql", { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -3256,6 +3640,18 @@ test('Add comment and label to found issues/associatedPR using the "successComme `https://api.github.local/repos/${owner}/${repo}/pulls/5/commits`, [{ sha: commits[1].hash }], ) + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getSRIssues("), + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -3584,6 +3980,20 @@ test('Does not comment/label associatedPR and relatedIssues created by "Bots"', {}, { body: ["released"] }, ) + .postOnce( + (url, { body }) => { + t.is(url, "https://api.github.local/graphql"); + t.regex(JSON.parse(body).query, /query getSRIssues\(/); + return true; + }, + { + data: { + repository: { + issues: { nodes: [] }, + }, + }, + }, + ) .getOnce( `https://api.github.local/search/issues?q=${encodeURIComponent( "in:title", @@ -3775,13 +4185,17 @@ test('Does not comment/label "associatedPR" when "successCommentCondition" disab {}, { body: ["released"] }, ) - .getOnce( - `https://api.github.local/search/issues?q=${encodeURIComponent( - "in:title", - )}+${encodeURIComponent(`repo:${owner}/${repo}`)}+${encodeURIComponent( - "type:issue", - )}+${encodeURIComponent("state:open")}+${encodeURIComponent(failTitle)}`, - { items: issues }, + .postOnce( + (url, { body }) => + url === "https://api.github.local/graphql" && + JSON.parse(body).query.includes("query getSRIssues("), + { + data: { + repository: { + issues: { nodes: issues }, + }, + }, + }, ) .patchOnce( `https://api.github.local/repos/${owner}/${repo}/issues/1`,
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: