diff --git a/__tests__/main.test.js b/__tests__/main.test.js index 02a4149..7177f26 100644 --- a/__tests__/main.test.js +++ b/__tests__/main.test.js @@ -44,6 +44,7 @@ beforeEach(() => { process.env.INPUT_MIN_COMBINE_NUMBER = '2' process.env.INPUT_LABELS = '' process.env.INPUT_AUTOCLOSE = 'true' + process.env.INPUT_UPDATE_BRANCH = 'true' jest.spyOn(github, 'getOctokit').mockImplementation(() => { return { @@ -1023,6 +1024,105 @@ test('successfully runs the action and sets labels when one PR has no CI defined ) }) +test('successfully runs the action and sets labels when one PR has no CI defined and the update_branch logic fails', async () => { + jest.spyOn(github, 'getOctokit').mockImplementation(() => { + return { + paginate: jest.fn().mockImplementation(() => { + return [ + buildPR(1, 'dependabot-1', ['question']), + buildPR(2, 'dependabot-2'), + buildPR(3, 'dependabot-3', ['nocombine']), + buildPR(4, 'dependabot-4'), + buildPR(5, 'dependabot-5'), + buildPR(6, 'dependabot-6'), + buildPR(7, 'fix-package') + ] + }), + graphql: jest.fn().mockImplementation((_query, params) => { + switch (params.pull_number) { + case 1: + case 2: + case 3: + return buildStatusResponse('APPROVED', 'SUCCESS') + case 4: + return buildStatusResponse('APPROVED', 'FAILURE') + case 5: + return buildStatusResponse(null, 'SUCCESS') + case 6: + return { + repository: { + pullRequest: { + reviewDecision: null, + commits: { + nodes: [ + { + commit: { + statusCheckRollup: null + } + } + ] + } + } + } + } + default: + throw new Error( + `params.pull_number of ${params.pull_number} is not configured.` + ) + } + }), + rest: { + issues: { + addLabels: jest.fn().mockReturnValueOnce({ + data: {} + }) + }, + git: { + createRef: jest.fn().mockReturnValueOnce({ + data: {} + }) + }, + repos: { + // mock the first value of merge to be a success and the second to be an exception + merge: jest + .fn() + .mockReturnValueOnce({ + data: { + merged: true + } + }) + .mockImplementation(() => { + throw new Error('merge error') + }) + }, + pulls: { + create: jest.fn().mockReturnValueOnce({ + data: { + number: 100, + html_url: 'https://github.com/test-owner/test-repo/pull/100' + } + }) + } + } + } + }) + + process.env.INPUT_REVIEW_REQUIRED = 'true' + process.env.INPUT_LABELS = 'label1,label2, label3' + expect(await run()).toBe('success') + + expect(infoMock).toHaveBeenCalledWith('Merged branch dependabot-1') + expect(warningMock).toHaveBeenCalledWith( + 'Failed to merge branch dependabot-2' + ) + expect(warningMock).toHaveBeenCalledWith('Failed to update combined pr branch with the base branch') + expect(setOutputMock).toHaveBeenCalledWith('pr_number', 100) + expect(setOutputMock).toHaveBeenCalledWith( + 'pr_url', + 'https://github.com/test-owner/test-repo/pull/100' + ) +}) + function buildStatusResponse(reviewDecision, ciStatus) { return { repository: { diff --git a/src/main.js b/src/main.js index d9433c4..ee7d4ad 100644 --- a/src/main.js +++ b/src/main.js @@ -24,6 +24,7 @@ export async function run() { core.getInput('min_combine_number', {required: true}) ) const autoclose = core.getInput('autoclose') === 'true' + const updateBranch = core.getBooleanInput('update_branch') // check for either prefix or regex if (branchPrefix === '' && branchRegex === '') { @@ -233,6 +234,22 @@ export async function run() { } } + // lastly, if the pull request's branch can be updated cleanly, update it + if (updateBranch === true) { + core.info('Attempting to update branch') + try { + await octokit.rest.repos.merge({ + owner: context.repo.owner, + repo: context.repo.repo, + base: baseBranch, + head: combineBranchName + }) + core.info('Branch updated') + } catch (error) { + core.warning('Failed to update combined pr branch with the base branch') + } + } + // output pull request url core.info('Combined PR url: ' + pullRequest.data.html_url) core.setOutput('pr_url', pullRequest.data.html_url)