From 6a1638a4ea1b7e39f941217b02344f3c4623beb7 Mon Sep 17 00:00:00 2001 From: Rob van der Leek <5324924+robvanderleek@users.noreply.github.com> Date: Sat, 2 Dec 2023 22:57:07 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20Use=20GraphQL=20API=20for?= =?UTF-8?q?=20signed=20empty=20commits=20(#787)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/github.js | 54 ++++++++++++++++++++------------------------ tests/github.test.js | 36 +++++++++++++++-------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/github.js b/src/github.js index 4d5048b8..6255cb7d 100644 --- a/src/github.js +++ b/src/github.js @@ -225,33 +225,6 @@ async function getBranchHeadSha (ctx, branch) { } } -async function getCommitTreeSha (ctx, commitSha) { - const owner = context.getRepoOwnerLogin(ctx) - const repo = context.getRepoName(ctx) - const res = await ctx.octokit.git.getCommit({ owner, repo, commit_sha: commitSha }) - return res.data.tree.sha -} - -async function createCommit (ctx, commitSha, treeSha, username, message) { - const owner = context.getRepoOwnerLogin(ctx) - const repo = context.getRepoName(ctx) - const res = await ctx.octokit.git.createCommit({ - owner, - repo, - message, - tree: treeSha, - parents: [commitSha], - author: { name: username, email: `${username}@users.noreply.github.com` } - }) - return res.data.sha -} - -async function updateReference (ctx, branchName, sha) { - const owner = context.getRepoOwnerLogin(ctx) - const repo = context.getRepoName(ctx) - await ctx.octokit.git.updateRef({ owner, repo, ref: `heads/${branchName}`, sha }) -} - async function createBranch (ctx, config, branchName, sha, log) { const owner = context.getRepoOwnerLogin(ctx) const repo = context.getRepoName(ctx) @@ -289,9 +262,7 @@ async function createPr (app, ctx, config, username, branchName) { const branchHeadSha = await getBranchHeadSha(ctx, branchName) if (branchHeadSha === baseHeadSha) { app.log('Branch and base heads are equal, creating empty commit for PR') - const treeSha = await getCommitTreeSha(ctx, branchHeadSha) - const emptyCommitSha = await createCommit(ctx, branchHeadSha, treeSha, username, getCommitText(ctx, config)) - await updateReference(ctx, branchName, emptyCommitSha) + await createEmptyCommit(ctx, branchName, getCommitText(ctx, config), branchHeadSha) } const { data: pr } = await ctx.octokit.pulls.create( { owner, repo, head: branchName, base, title, body: getPrBody(app, ctx, config), draft: draft }) @@ -303,6 +274,29 @@ async function createPr (app, ctx, config, username, branchName) { } } +async function createEmptyCommit (ctx, branchName, message, headSha) { + const owner = context.getRepoOwnerLogin(ctx) + const repo = context.getRepoName(ctx) + const createEptyCommitMutation = ` + mutation($repositoryNameWithOwner: String!, $branchName: String!, $message: String!, $headSha: GitObjectID!) { + createCommitOnBranch( + input: { + branch: {repositoryNameWithOwner: $repositoryNameWithOwner, branchName: $branchName}, + message: {headline: $message}, + fileChanges: {}, + expectedHeadOid: $headSha + } + ) { + commit { + url + } + } + }` + await ctx.octokit.graphql(createEptyCommitMutation, { + repositoryNameWithOwner: `${owner}/${repo}`, branchName: branchName, message: message, headSha: headSha + }) +} + function getCommitText (ctx, config) { const draft = Config.shouldOpenDraftPR(config) const draftText = draft ? 'draft ' : '' diff --git a/tests/github.test.js b/tests/github.test.js index e5e38259..34ffe40f 100644 --- a/tests/github.test.js +++ b/tests/github.test.js @@ -203,13 +203,11 @@ test('Retry create comment when it fails', async () => { test('create (draft) PR', async () => { const createPR = jest.fn() let capturedCommitMessage = '' - const createCommit = ({ message }) => { - capturedCommitMessage = message - return ({ data: { sha: 'abcd1234' } }) - } const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR - ctx.octokit.git.createCommit = createCommit + ctx.octokit.graphql = (_, { message }) => { + capturedCommitMessage = message + } await github.createPr({ log: () => { } }, ctx, { silent: false }, 'robvanderleek', 'issue-1') expect(createPR).toHaveBeenCalledWith({ @@ -237,11 +235,10 @@ test('create (draft) PR', async () => { test('copy Issue description into PR', async () => { const createPR = jest.fn() - const createCommit = () => ({ data: { sha: 'abcd1234' } }) const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR - ctx.octokit.git.createCommit = createCommit ctx.payload.issue.body = 'This is the description' + ctx.octokit.graphql = jest.fn() await github.createPr({ log: () => { } }, ctx, { copyIssueDescriptionToPR: true, silent: false }, 'robvanderleek', 'issue-1') @@ -259,11 +256,10 @@ test('copy Issue description into PR', async () => { test('Do not copy undefined Issue description into PR', async () => { const createPR = jest.fn() - const createCommit = () => ({ data: { sha: 'abcd1234' } }) const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR - ctx.octokit.git.createCommit = createCommit ctx.payload.issue.body = null + ctx.octokit.graphql = jest.fn() await github.createPr({ log: () => { } }, ctx, { copyIssueDescriptionToPR: true, silent: false }, 'robvanderleek', 'issue-1') @@ -282,6 +278,7 @@ test('use correct source branch', async () => { const createPR = jest.fn() const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR + ctx.octokit.graphql = jest.fn() ctx.payload.issue.labels = [{ name: 'enhancement' }] const config = { branches: [{ label: 'enhancement', name: 'develop' }] } @@ -301,6 +298,7 @@ test('use configured target branch', async () => { const createPR = jest.fn() const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR + ctx.octokit.graphql = jest.fn() ctx.payload.issue.labels = [{ name: 'enhancement' }] const config = { branches: [{ label: 'enhancement', prTarget: 'develop' }] } @@ -320,6 +318,7 @@ test('configured source and target branch', async () => { const createPR = jest.fn() const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = createPR + ctx.octokit.graphql = jest.fn() ctx.payload.issue.labels = [{ name: 'hotfix' }] const config = { branches: [{ label: 'hotfix', name: 'develop', prTarget: 'hotfix' }] } @@ -337,11 +336,10 @@ test('configured source and target branch', async () => { test('copy Issue milestone into PR', async () => { const updateIssue = jest.fn() - const createCommit = () => ({ data: { sha: 'abcd1234' } }) const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = () => ({ data: { number: 123 } }) ctx.octokit.issues.update = updateIssue - ctx.octokit.git.createCommit = createCommit + ctx.octokit.graphql = jest.fn() ctx.payload.issue.body = 'This is the description' ctx.payload.issue.milestone = { number: 456 } @@ -353,27 +351,31 @@ test('copy Issue milestone into PR', async () => { }) test('empty commit text', async () => { - const createCommit = jest.fn() const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = () => ({ data: { number: 123 } }) - ctx.octokit.git.createCommit = createCommit + let capturedCommitMessage = '' + ctx.octokit.graphql = (_, { message }) => { + capturedCommitMessage = message + } ctx.payload.issue.body = 'This is the description' ctx.payload.issue.milestone = { number: 456 } await github.createPr({ log: () => { } }, ctx, {}, 'robvanderleek', 'issue-1') - expect(createCommit.mock.calls[0][0].message).toBe('Create PR for #1') + expect(capturedCommitMessage).toBe('Create PR for #1') }) test('empty commit with skip CI text', async () => { - const createCommit = jest.fn() const ctx = helpers.getDefaultContext() ctx.octokit.pulls.create = () => ({ data: { number: 123 } }) - ctx.octokit.git.createCommit = createCommit + let capturedCommitMessage = '' + ctx.octokit.graphql = (_, { message }) => { + capturedCommitMessage = message + } ctx.payload.issue.body = 'This is the description' ctx.payload.issue.milestone = { number: 456 } await github.createPr({ log: () => { } }, ctx, { prSkipCI: true }, 'robvanderleek', 'issue-1') - expect(createCommit.mock.calls[0][0].message).toBe('Create PR for #1\n[skip ci]') + expect(capturedCommitMessage).toBe('Create PR for #1\n[skip ci]') })