From 9d75403c59dca8f6a9de8df717544085a686cd4f Mon Sep 17 00:00:00 2001 From: Olabode Lawal-Shittabey Date: Thu, 5 Sep 2024 13:35:28 +0100 Subject: [PATCH] Revert "feat: verify OAuth scopes of classic GitHub PATs (#897)" This reverts commit be071a27166294c0eba55da7990b2a963a7732c6. --- lib/definitions/errors.js | 18 +- lib/verify.js | 17 +- test/integration.test.js | 68 +------- test/verify.test.js | 336 +------------------------------------- 4 files changed, 19 insertions(+), 420 deletions(-) diff --git a/lib/definitions/errors.js b/lib/definitions/errors.js index 3cdbde55..74fa1ce2 100644 --- a/lib/definitions/errors.js +++ b/lib/definitions/errors.js @@ -178,24 +178,12 @@ If you are using [GitHub Enterprise](https://enterprise.github.com) please make export function EGHNOPERMISSION({ owner, repo }) { return { - message: `The GitHub token doesn't allow to push to and maintain the repository ${owner}/${repo}.`, + message: `The GitHub token doesn't allow to push on the repository ${owner}/${repo}.`, details: `The user associated with the [GitHub token](${linkify( "README.md#github-authentication", - )}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must have permission to push to and maintain the repository ${owner}/${repo}. + )}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must allows to push to the repository ${owner}/${repo}. -Please make sure the GitHub user associated with the token is an [owner](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#owner-access-on-a-repository-owned-by-a-user-account) or a [collaborator](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#collaborator-access-on-a-repository-owned-by-a-user-account) if the repository belongs to a user account or has [write permissions](https://help.github.com/articles/managing-team-access-to-an-organization-repository) if the repository [belongs to an organization](https://help.github.com/articles/repository-permission-levels-for-an-organization).`, - }; -} - -export function EGHNOSCOPE({ scopes }) { - return { - message: `The GitHub token doesn't have the necessary OAuth scopes to write contents, issues, and pull requests.`, - details: `The [GitHub token](${linkify( - "README.md#github-authentication", - )}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must have the correct scopes. -${scopes ? `\nThe token you used has scopes: ${scopes.join(", ")}\n` : ""} -For classic PATs, make sure the token has the \`repo\` scope if the repository is private, or \`public_repo\` scope otherwise. -For fine-grained PATs, make sure the token has the \`content: write\`, \`issues: write\`, and \`pull_requests: write\` scopes on the repository.`, +Please make sure the GitHub user associated with the token is an [owner](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#owner-access-on-a-repository-owned-by-a-user-account) or a [collaborator](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#collaborator-access-on-a-repository-owned-by-a-user-account) if the repository belong to a user account or has [write permissions](https://help.github.com/articles/managing-team-access-to-an-organization-repository) if the repository [belongs to an organization](https://help.github.com/articles/repository-permission-levels-for-an-organization).`, }; } diff --git a/lib/verify.js b/lib/verify.js index 997f80ef..3f348809 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -107,21 +107,8 @@ export default async function verify(pluginConfig, context, { Octokit }) { ); try { const { - headers, - data: { private: _private, permissions, clone_url }, + data: { permissions, clone_url }, } = await octokit.request("GET /repos/{owner}/{repo}", { repo, owner }); - - // GitHub only returns this header if the token is a classic PAT - if (headers?.["x-oauth-scopes"]) { - const scopes = headers["x-oauth-scopes"].split(/\s*,\s*/g); - if ( - !scopes.includes("repo") && - (_private || !scopes.includes("public_repo")) - ) { - errors.push(getError("EGHNOSCOPE", { scopes })); - } - } - // Verify if Repository Name wasn't changed const parsedCloneUrl = parseGithubUrl(clone_url); if ( @@ -137,7 +124,7 @@ export default async function verify(pluginConfig, context, { Octokit }) { // Do not check for permissions in GitHub actions, as the provided token is an installation access token. // octokit.request("GET /repos/{owner}/{repo}", {repo, owner}) does not return the "permissions" key in that case. // But GitHub Actions have all permissions required for @semantic-release/github to work - if (!env.GITHUB_ACTION && !(permissions?.push && permissions?.maintain)) { + if (!env.GITHUB_ACTION && !permissions?.push) { // If authenticated as GitHub App installation, `push` will always be false. // We send another request to check if current authentication is an installation. // Note: we cannot check if the installation has all required permissions, it's diff --git a/test/integration.test.js b/test/integration.test.js index 7b5a29ad..f512c7fa 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -29,7 +29,6 @@ test("Verify GitHub auth", async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -50,43 +49,6 @@ test("Verify GitHub auth", async (t) => { t.true(fetch.done()); }); -test("Throws when GitHub user lacks maintain permission", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GITHUB_TOKEN: "github_token" }; - const options = { - repositoryUrl: `git+https://othertesturl.com/${owner}/${repo}.git`, - }; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: false, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }); - - const { - errors: [error], - } = await t.throwsAsync( - t.context.m.verifyConditions( - {}, - { cwd, env, options, logger: t.context.logger }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - - t.is(error.code, "EGHNOPERMISSION"); - t.true(fetch.done()); -}); - test("Verify GitHub auth with publish options", async (t) => { const owner = "test_user"; const repo = "test_repo"; @@ -100,7 +62,6 @@ test("Verify GitHub auth with publish options", async (t) => { .get(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -141,7 +102,6 @@ test("Verify GitHub auth and assets config", async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -248,7 +208,6 @@ test("Publish a release with an array of assets", async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) @@ -344,7 +303,6 @@ test("Publish a release with release information in assets", async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) @@ -418,7 +376,6 @@ test("Update a release", async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) @@ -485,10 +442,7 @@ test("Comment and add labels on PR included in the releases", async (t) => { .get( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, full_name: `${owner}/${repo}`, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }, @@ -596,10 +550,7 @@ test("Open a new issue with the list of errors", async (t) => { .get( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, full_name: `${owner}/${repo}`, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }, @@ -694,10 +645,7 @@ test("Verify, release and notify success", async (t) => { .get( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, full_name: `${owner}/${repo}`, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }, @@ -863,10 +811,7 @@ test("Verify, update release and notify success", async (t) => { .get( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, full_name: `${owner}/${repo}`, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }, @@ -1004,10 +949,7 @@ test("Verify and notify failure", async (t) => { .get( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, full_name: `${owner}/${repo}`, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }, diff --git a/test/verify.test.js b/test/verify.test.js index 90c92cd3..495c7b1b 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -15,7 +15,7 @@ test.beforeEach((t) => { t.context.logger = { log: t.context.log, error: t.context.error }; }); -test("Verify package, token and repository access for private repo with token scopes: repo", async (t) => { +test("Verify package, token and repository access", async (t) => { const owner = "test_user"; const repo = "test_repo"; const env = { GH_TOKEN: "github_token" }; @@ -30,131 +30,10 @@ test("Verify package, token and repository access for private repo with token sc const fetch = fetchMock .sandbox() .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - headers: { - "x-oauth-scopes": "repo", - }, - body: { - private: true, - permissions: { - push: true, - maintain: true, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }, - }); - - await t.notThrowsAsync( - verify( - { - proxy, - assets, - successComment, - failTitle, - failComment, - labels, - discussionCategoryName, - }, - { - env, - options: { - repositoryUrl: `git+https://othertesturl.com/${owner}/${repo}.git`, - }, - logger: t.context.logger, - }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - t.true(fetch.done()); -}); - -test("Verify package, token and repository access for public repo with token scopes: repo", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GH_TOKEN: "github_token" }; - const proxy = "https://localhost"; - const assets = [{ path: "lib/file.js" }, "file.js"]; - const successComment = "Test comment"; - const failTitle = "Test title"; - const failComment = "Test comment"; - const labels = ["semantic-release"]; - const discussionCategoryName = "Announcements"; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - headers: { - "x-oauth-scopes": "repo", - }, - body: { - private: false, - permissions: { - push: true, - maintain: true, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }, - }); - - await t.notThrowsAsync( - verify( - { - proxy, - assets, - successComment, - failTitle, - failComment, - labels, - discussionCategoryName, - }, - { - env, - options: { - repositoryUrl: `git+https://othertesturl.com/${owner}/${repo}.git`, - }, - logger: t.context.logger, - }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - t.true(fetch.done()); -}); - -test("Verify package, token and repository access for public repo with token scopes: public_repo", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GH_TOKEN: "github_token" }; - const proxy = "https://localhost"; - const assets = [{ path: "lib/file.js" }, "file.js"]; - const successComment = "Test comment"; - const failTitle = "Test title"; - const failComment = "Test comment"; - const labels = ["semantic-release"]; - const discussionCategoryName = "Announcements"; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - headers: { - "x-oauth-scopes": "public_repo", - }, - body: { - private: false, - permissions: { - push: true, - maintain: true, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, + permissions: { + push: true, }, + clone_url: `https://api.github.local/${owner}/${repo}.git`, }); await t.notThrowsAsync( @@ -203,7 +82,6 @@ test('Verify package, token and repository access with "proxy", "asset", "discus .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -249,7 +127,6 @@ test("Verify package, token and repository access and custom URL with prefix", a .getOnce(`https://othertesturl.com:9090/prefix/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -291,7 +168,6 @@ test("Verify package, token and repository access and custom URL without prefix" .getOnce(`https://othertesturl.com:9090/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -333,7 +209,6 @@ test("Verify package, token and repository access and shorthand repositoryUrl UR .getOnce(`https://othertesturl.com:9090/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -376,7 +251,6 @@ test("Verify package, token and repository with environment variables", async (t .getOnce(`https://othertesturl.com:443/prefix/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }); @@ -421,7 +295,6 @@ test("Verify package, token and repository access with alternative environment v .getOnce(`https://othertesturl.com:443/prefix/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }); @@ -459,7 +332,6 @@ test("Verify package, token and repository access with custom API URL", async (t .getOnce(`https://api.othertesturl.com:9090/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }); @@ -502,7 +374,6 @@ test("Verify package, token and repository access with API URL in environment va .getOnce(`https://api.othertesturl.com:443/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `htttps://api.github.local/${owner}/${repo}.git`, }); @@ -539,7 +410,6 @@ test('Verify "proxy" is a String', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -575,7 +445,6 @@ test('Verify "proxy" is an object with "host" and "port" properties', async (t) .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -613,7 +482,6 @@ test('Verify "proxy" is a Boolean set to false', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -649,7 +517,6 @@ test('Verify "assets" is a String', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -685,7 +552,6 @@ test('Verify "assets" is an Object with a path property', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -721,7 +587,6 @@ test('Verify "assets" is an Array of Object with a path property', async (t) => .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -759,7 +624,6 @@ test('Verify "assets" is an Array of glob Arrays', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -795,7 +659,6 @@ test('Verify "assets" is an Array of Object with a glob Arrays in path property' .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -833,7 +696,6 @@ test('Verify "labels" is a String', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -869,7 +731,6 @@ test('Verify "assignees" is a String', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -905,7 +766,6 @@ test('Verify "addReleases" is a valid string (top)', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -941,7 +801,6 @@ test('Verify "addReleases" is a valid string (bottom)', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -977,7 +836,6 @@ test('Verify "addReleases" is valid (false)', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1013,7 +871,6 @@ test('Verify "draftRelease" is valid (true)', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1049,7 +906,6 @@ test('Verify "draftRelease" is valid (false)', async (t) => { .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1298,99 +1154,7 @@ test("Throw SemanticReleaseError for invalid repositoryUrl", async (t) => { t.is(error.code, "EINVALIDGITHUBURL"); }); -test("Throw SemanticReleaseError if token doesn't have the repo or public_repo scope on a public repository", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GH_TOKEN: "github_token" }; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - headers: { - "x-oauth-scopes": "repo:status, repo_deployment", - }, - body: { - private: false, - permissions: { - push: true, - maintain: true, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }, - }); - - const { - errors: [error, ...errors], - } = await t.throwsAsync( - verify( - {}, - { - env, - options: { repositoryUrl: `https://github.com/${owner}/${repo}.git` }, - logger: t.context.logger, - }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - - t.is(errors.length, 0); - t.is(error.name, "SemanticReleaseError"); - t.is(error.code, "EGHNOSCOPE"); - t.true(fetch.done()); -}); - -test("Throw SemanticReleaseError if token doesn't have the repo scope on a private repository", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GH_TOKEN: "github_token" }; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - headers: { - "x-oauth-scopes": "repo:status, repo_deployment", - }, - body: { - private: true, - permissions: { - push: true, - maintain: true, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }, - }); - - const { - errors: [error, ...errors], - } = await t.throwsAsync( - verify( - {}, - { - env, - options: { repositoryUrl: `https://github.com/${owner}/${repo}.git` }, - logger: t.context.logger, - }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - - t.is(errors.length, 0); - t.is(error.name, "SemanticReleaseError"); - t.is(error.code, "EGHNOSCOPE"); - t.true(fetch.done()); -}); - -test("Throw SemanticReleaseError if user doesn't have the push permission on the repository and it's not a Github installation token", async (t) => { +test("Throw SemanticReleaseError if token doesn't have the push permission on the repository and it's not a Github installation token", async (t) => { const owner = "test_user"; const repo = "test_repo"; const env = { GH_TOKEN: "github_token" }; @@ -1400,7 +1164,6 @@ test("Throw SemanticReleaseError if user doesn't have the push permission on the .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: false, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }) @@ -1434,51 +1197,7 @@ test("Throw SemanticReleaseError if user doesn't have the push permission on the t.true(fetch.done()); }); -test("Throw SemanticReleaseError if user doesn't have the maintain permission on the repository and it's not a Github installation token", async (t) => { - const owner = "test_user"; - const repo = "test_repo"; - const env = { GH_TOKEN: "github_token" }; - - const fetch = fetchMock - .sandbox() - .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: false, - }, - clone_url: `https://api.github.local/${owner}/${repo}.git`, - }) - .headOnce( - "https://api.github.local/installation/repositories?per_page=1", - 403, - ); - - const { - errors: [error, ...errors], - } = await t.throwsAsync( - verify( - {}, - { - env, - options: { repositoryUrl: `https://github.com/${owner}/${repo}.git` }, - logger: t.context.logger, - }, - { - Octokit: TestOctokit.defaults((options) => ({ - ...options, - request: { ...options.request, fetch }, - })), - }, - ), - ); - - t.is(errors.length, 0); - t.is(error.name, "SemanticReleaseError"); - t.is(error.code, "EGHNOPERMISSION"); - t.true(fetch.done()); -}); - -test("Do not throw SemanticReleaseError if user doesn't have the push permission but it is a Github installation token", async (t) => { +test("Do not throw SemanticReleaseError if token doesn't have the push permission but it is a Github installation token", async (t) => { const owner = "test_user"; const repo = "test_repo"; const env = { GH_TOKEN: "github_token" }; @@ -1556,7 +1275,7 @@ test(`Don't throw an error if owner/repo only differs in case`, async (t) => { const fetch = fetchMock.sandbox().getOnce( `https://api.github.local/repos/org/foo`, { - permissions: { push: true, maintain: true }, + permissions: { push: true }, clone_url: `https://github.com/ORG/FOO.git`, }, { repeat: 2 }, @@ -1603,10 +1322,7 @@ for (const makeRepositoryUrl of urlFormats) { const fetch = fetchMock.sandbox().getOnce( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, clone_url: make_clone_url(owner, repo), }, { repeat: 2 }, @@ -1641,10 +1357,7 @@ for (const makeRepositoryUrl of urlFormats) { const fetch = fetchMock.sandbox().getOnce( `https://api.github.local/repos/${owner}/${repo}`, { - permissions: { - push: true, - maintain: true, - }, + permissions: { push: true }, clone_url: make_clone_url(owner, repo2), }, { repeat: 2 }, @@ -1778,7 +1491,6 @@ test('Throw SemanticReleaseError if "assets" option is not a String or an Array .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1819,7 +1531,6 @@ test('Throw SemanticReleaseError if "assets" option is an Array with invalid ele .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1860,7 +1571,6 @@ test('Throw SemanticReleaseError if "assets" option is an Object missing the "pa .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1901,7 +1611,6 @@ test('Throw SemanticReleaseError if "assets" option is an Array with objects mis .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1942,7 +1651,6 @@ test('Throw SemanticReleaseError if "successComment" option is not a String', as .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -1983,7 +1691,6 @@ test('Throw SemanticReleaseError if "successComment" option is an empty String', .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2024,7 +1731,6 @@ test('Throw SemanticReleaseError if "successComment" option is a whitespace Stri .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2065,7 +1771,6 @@ test('Throw SemanticReleaseError if "failTitle" option is not a String', async ( .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2106,7 +1811,6 @@ test('Throw SemanticReleaseError if "failTitle" option is an empty String', asyn .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2147,7 +1851,6 @@ test('Throw SemanticReleaseError if "failTitle" option is a whitespace String', .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2188,7 +1891,6 @@ test('Throw SemanticReleaseError if "discussionCategoryName" option is not a Str .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2229,7 +1931,6 @@ test('Throw SemanticReleaseError if "discussionCategoryName" option is an empty .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2270,7 +1971,6 @@ test('Throw SemanticReleaseError if "discussionCategoryName" option is a whitesp .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2311,7 +2011,6 @@ test('Throw SemanticReleaseError if "failComment" option is not a String', async .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2352,7 +2051,6 @@ test('Throw SemanticReleaseError if "failComment" option is an empty String', as .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2393,7 +2091,6 @@ test('Throw SemanticReleaseError if "failComment" option is a whitespace String' .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2434,7 +2131,6 @@ test('Throw SemanticReleaseError if "labels" option is not a String or an Array .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2475,7 +2171,6 @@ test('Throw SemanticReleaseError if "labels" option is an Array with invalid ele .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2516,7 +2211,6 @@ test('Throw SemanticReleaseError if "labels" option is a whitespace String', asy .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2557,7 +2251,6 @@ test('Throw SemanticReleaseError if "assignees" option is not a String or an Arr .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2598,7 +2291,6 @@ test('Throw SemanticReleaseError if "assignees" option is an Array with invalid .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2639,7 +2331,6 @@ test('Throw SemanticReleaseError if "assignees" option is a whitespace String', .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2680,7 +2371,6 @@ test('Throw SemanticReleaseError if "releasedLabels" option is not a String or a .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2721,7 +2411,6 @@ test('Throw SemanticReleaseError if "releasedLabels" option is an Array with inv .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2762,7 +2451,6 @@ test('Throw SemanticReleaseError if "releasedLabels" option is a whitespace Stri .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2803,7 +2491,6 @@ test('Throw SemanticReleaseError if "addReleases" option is not a valid string ( .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2844,7 +2531,6 @@ test('Throw SemanticReleaseError if "addReleases" option is not a valid string ( .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2885,7 +2571,6 @@ test('Throw SemanticReleaseError if "addReleases" option is not a valid string ( .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2926,7 +2611,6 @@ test('Throw SemanticReleaseError if "draftRelease" option is not a valid boolean .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -2966,7 +2650,6 @@ test('Throw SemanticReleaseError if "releaseBodyTemplate" option is an empty str .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, }); @@ -3006,7 +2689,6 @@ test('Throw SemanticReleaseError if "releaseNameTemplate" option is an empty str .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { permissions: { push: true, - maintain: true, }, clone_url: `https://api.github.local/${owner}/${repo}.git`, });