From 055682061716e713af07fd86ca9be5ed12e6487b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 29 Apr 2019 10:26:38 +0200 Subject: [PATCH] Update message about conflict resolution (#120) --- package.json | 8 +- src/steps/doBackportVersions.ts | 10 +- .../doBackportVersions.test.ts.snap | 59 ++-- test/steps/doBackportVersions.test.ts | 271 ++++++++++++------ yarn.lock | 7 + 5 files changed, 227 insertions(+), 128 deletions(-) diff --git a/package.json b/package.json index 79da4f2c..1fd38e68 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,12 @@ "ts", "js", "json" - ] + ], + "globals": { + "ts-jest": { + "diagnostics": false + } + } }, "engines": { "node": ">=8.0.0" @@ -96,6 +101,7 @@ "@types/lodash.get": "^4.4.6", "@types/lodash.isempty": "^4.4.6", "@types/lodash.isstring": "^4.0.6", + "@types/lodash.last": "^3.0.6", "@types/mkdirp": "^0.5.2", "@types/nock": "^10.0.0", "@types/node": "^10.14.4", diff --git a/src/steps/doBackportVersions.ts b/src/steps/doBackportVersions.ts index 3f54cb5e..92723b34 100644 --- a/src/steps/doBackportVersions.ts +++ b/src/steps/doBackportVersions.ts @@ -132,12 +132,16 @@ async function cherrypickAndConfirm( await cherrypick({ owner, repoName, sha }); spinner.succeed(); } catch (e) { - spinner.fail( - `Cherry-picking failed. Please resolve conflicts in: ${getRepoPath( + spinner.fail(`Cherry-picking failed.\n`); + log( + `Please resolve conflicts in: ${getRepoPath( owner, repoName - )}` + )} and when all conflicts have been resolved and staged run:` ); + log(` + git cherry-pick --continue + `); const hasConflict = e.cmd.includes('git cherry-pick'); if (!hasConflict) { diff --git a/test/steps/__snapshots__/doBackportVersions.test.ts.snap b/test/steps/__snapshots__/doBackportVersions.test.ts.snap index f32acc64..9138d4de 100644 --- a/test/steps/__snapshots__/doBackportVersions.test.ts.snap +++ b/test/steps/__snapshots__/doBackportVersions.test.ts.snap @@ -1,13 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`doBackportVersion with pull request reference 1`] = ` -Object { - "html_url": "myHtmlUrl", - "number": 1337, -} -`; - -exports[`doBackportVersion with pull request reference 2`] = ` +exports[`doBackportVersion when cherry-picking fails and conflicts were not resolved 2`] = ` Array [ Array [ "git reset --hard && git clean -d --force && git checkout master && git pull origin master", @@ -18,7 +11,7 @@ Array [ [Function], ], Array [ - "git fetch origin 6.x && git branch backport/6.x/pr-1000_pr-2000 origin/6.x --force && git checkout backport/6.x/pr-1000_pr-2000 ", + "git fetch origin 6.x && git branch backport/6.x/commit-mySha origin/6.x --force && git checkout backport/6.x/commit-mySha ", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, @@ -33,33 +26,10 @@ Array [ }, [Function], ], - Array [ - "git cherry-pick mySha2", - Object { - "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", - "maxBuffer": 104857600, - }, - [Function], - ], - Array [ - "git push sqren backport/6.x/pr-1000_pr-2000:backport/6.x/pr-1000_pr-2000 --force", - Object { - "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", - "maxBuffer": 104857600, - }, - [Function], - ], ] `; -exports[`doBackportVersion without pull request reference 1`] = ` -Object { - "html_url": "myHtmlUrl", - "number": 1337, -} -`; - -exports[`doBackportVersion without pull request reference 2`] = ` +exports[`doBackportVersion when cherry-picking fails and conflicts were resolved 1`] = ` Array [ Array [ "git reset --hard && git clean -d --force && git checkout master && git pull origin master", @@ -70,7 +40,7 @@ Array [ [Function], ], Array [ - "git fetch origin 6.x && git branch backport/6.x/pr-1000_pr-2000 origin/6.x --force && git checkout backport/6.x/pr-1000_pr-2000 ", + "git fetch origin 6.x && git branch backport/6.x/commit-mySha origin/6.x --force && git checkout backport/6.x/commit-mySha ", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, @@ -86,7 +56,7 @@ Array [ [Function], ], Array [ - "git cherry-pick mySha2", + "git diff-index --quiet HEAD --", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, @@ -94,13 +64,18 @@ Array [ [Function], ], Array [ - "git push sqren backport/6.x/pr-1000_pr-2000:backport/6.x/pr-1000_pr-2000 --force", + "git push sqren backport/6.x/commit-mySha:backport/6.x/commit-mySha --force", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, }, [Function], ], +] +`; + +exports[`doBackportVersion when commit has a pull request reference should make correct git commands 1`] = ` +Array [ Array [ "git reset --hard && git clean -d --force && git checkout master && git pull origin master", Object { @@ -110,7 +85,7 @@ Array [ [Function], ], Array [ - "git fetch origin 6.x && git branch backport/6.x/commit-mySha origin/6.x --force && git checkout backport/6.x/commit-mySha ", + "git fetch origin 6.x && git branch backport/6.x/pr-1000_pr-2000 origin/6.x --force && git checkout backport/6.x/pr-1000_pr-2000 ", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, @@ -126,7 +101,15 @@ Array [ [Function], ], Array [ - "git push sqren backport/6.x/commit-mySha:backport/6.x/commit-mySha --force", + "git cherry-pick mySha2", + Object { + "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", + "maxBuffer": 104857600, + }, + [Function], + ], + Array [ + "git push sqren backport/6.x/pr-1000_pr-2000:backport/6.x/pr-1000_pr-2000 --force", Object { "cwd": "/myHomeDir/.backport/repositories/elastic/kibana", "maxBuffer": 104857600, diff --git a/test/steps/doBackportVersions.test.ts b/test/steps/doBackportVersions.test.ts index 1aaee8e7..2f5a9381 100644 --- a/test/steps/doBackportVersions.test.ts +++ b/test/steps/doBackportVersions.test.ts @@ -1,104 +1,203 @@ import axios from 'axios'; -import nock from 'nock'; -import httpAdapter from 'axios/lib/adapters/http'; import * as childProcess from 'child_process'; import { doBackportVersion, getReferenceLong } from '../../src/steps/doBackportVersions'; - -axios.defaults.adapter = httpAdapter; +import { PromiseReturnType } from '../../src/types/commons'; +import last from 'lodash.last'; +import * as prompts from '../../src/services/prompts'; +import * as logger from '../../src/services/logger'; describe('doBackportVersion', () => { - let addLabelMock: nock.Scope; + let axiosMockInstance: jest.Mock; + beforeEach(() => { - addLabelMock = nock('https://api.github.com') - .post(`/repos/elastic/kibana/issues/1337/labels`, ['backport']) - .query(true) - .reply(200, {}); + axiosMockInstance = jest + .spyOn(axios, 'post') + // mock: createPullRequest + // @ts-ignore + .mockResolvedValueOnce({ + data: { + number: 1337, + html_url: 'myHtmlUrl' + } + }) + // mock: addLabelsToPullRequest + .mockResolvedValueOnce(null); }); - it('with pull request reference', async () => { - const createPRMock = nock('https://api.github.com') - .post(`/repos/elastic/kibana/pulls`, { - title: '[6.x] myCommitMessage | myOtherCommitMessage', - body: - 'Backports the following commits to 6.x:\n - myCommitMessage (#1000)\n - myOtherCommitMessage (#2000)', - head: 'sqren:backport/6.x/pr-1000_pr-2000', - base: '6.x' - }) - .query(true) - .reply(200, { - number: 1337, - html_url: 'myHtmlUrl' - }); + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('when commit has a pull request reference', () => { + let execSpy: jest.SpyInstance; + let res: PromiseReturnType; + beforeEach(async () => { + const commits = [ + { + sha: 'mySha', + message: 'myCommitMessage', + pullNumber: 1000 + }, + { + sha: 'mySha2', + message: 'myOtherCommitMessage', + pullNumber: 2000 + } + ]; - const commits = [ - { - sha: 'mySha', - message: 'myCommitMessage', - pullNumber: 1000 - }, - { - sha: 'mySha2', - message: 'myOtherCommitMessage', - pullNumber: 2000 - } - ]; - - const execSpy = jest.spyOn(childProcess, 'exec'); - - const res = await doBackportVersion( - 'elastic', - 'kibana', - commits, - '6.x', - 'sqren', - ['backport'] - ); - - expect(res).toMatchSnapshot(); - expect(execSpy.mock.calls).toMatchSnapshot(); - expect(createPRMock.isDone()).toBe(true); - expect(addLabelMock.isDone()).toBe(true); + execSpy = jest.spyOn(childProcess, 'exec'); + + res = await doBackportVersion( + 'elastic', + 'kibana', + commits, + '6.x', + 'sqren', + ['backport'] + ); + }); + + it('should make correct git commands', () => { + expect(execSpy.mock.calls).toMatchSnapshot(); + }); + + it('should return correct response', () => { + expect(res).toEqual({ html_url: 'myHtmlUrl', number: 1337 }); + }); + + it('should create pull request and add labels', () => { + expect(axiosMockInstance).toHaveBeenCalledTimes(2); + expect(axiosMockInstance).toHaveBeenNthCalledWith( + 1, + 'https://api.github.com/repos/elastic/kibana/pulls?access_token=undefined', + { + title: '[6.x] myCommitMessage | myOtherCommitMessage', + body: + 'Backports the following commits to 6.x:\n - myCommitMessage (#1000)\n - myOtherCommitMessage (#2000)', + head: 'sqren:backport/6.x/pr-1000_pr-2000', + base: '6.x' + } + ); + + expect(axiosMockInstance).toHaveBeenNthCalledWith( + 2, + 'https://api.github.com/repos/elastic/kibana/issues/1337/labels?access_token=undefined', + ['backport'] + ); + }); }); - it('without pull request reference', async () => { - const createPRMock = nock('https://api.github.com') - .post(`/repos/elastic/kibana/pulls`, { - title: '[6.x] myCommitMessage', - body: - 'Backports the following commits to 6.x:\n - myCommitMessage (mySha)', - head: 'sqren:backport/6.x/commit-mySha', - base: '6.x' - }) - .query(true) - .reply(200, { - number: 1337, - html_url: 'myHtmlUrl' - }); + describe('when commit does not have a pull request reference', () => { + beforeEach(async () => { + const commits = [ + { + sha: 'mySha', + message: 'myCommitMessage' + } + ]; - const commits = [ - { - sha: 'mySha', - message: 'myCommitMessage' - } - ]; - - const execSpy = jest.spyOn(childProcess, 'exec'); - - const res = await doBackportVersion( - 'elastic', - 'kibana', - commits, - '6.x', - 'sqren' - ); - - expect(res).toMatchSnapshot(); - expect(execSpy.mock.calls).toMatchSnapshot(); - expect(createPRMock.isDone()).toBe(true); - expect(addLabelMock.isDone()).toBe(false); + await doBackportVersion('elastic', 'kibana', commits, '6.x', 'sqren', [ + 'backport' + ]); + }); + + it('should create pull request and add labels', () => { + expect(axiosMockInstance).toHaveBeenCalledTimes(2); + expect(axiosMockInstance).toHaveBeenNthCalledWith( + 1, + 'https://api.github.com/repos/elastic/kibana/pulls?access_token=undefined', + { + title: '[6.x] myCommitMessage', + body: + 'Backports the following commits to 6.x:\n - myCommitMessage (mySha)', + head: 'sqren:backport/6.x/commit-mySha', + base: '6.x' + } + ); + + expect(axiosMockInstance).toHaveBeenNthCalledWith( + 2, + 'https://api.github.com/repos/elastic/kibana/issues/1337/labels?access_token=undefined', + ['backport'] + ); + }); + }); + + describe('when cherry-picking fails', () => { + function didResolveConflict(didResolve: boolean) { + const logSpy = jest.spyOn(logger, 'log'); + const commits = [ + { + sha: 'mySha', + message: 'myCommitMessage' + } + ]; + + const execSpy = jest + .spyOn(childProcess, 'exec') + .mockImplementation((...args: any[]) => { + const [cmd] = args; + if (cmd.includes('git cherry-pick')) { + const e = new Error('as'); + // @ts-ignore + e.cmd = cmd; + throw e; + } else { + last(args)(); + } + + return {} as any; + }); + + spyOn(prompts, 'confirmPrompt').and.returnValue(didResolve); + + const promise = doBackportVersion( + 'elastic', + 'kibana', + commits, + '6.x', + 'sqren', + ['backport'] + ); + + return { logSpy, execSpy, promise }; + } + + it('and conflicts were resolved', async () => { + const { execSpy, promise } = didResolveConflict(true); + await promise; + expect(execSpy.mock.calls).toMatchSnapshot(); + expect(axiosMockInstance).toHaveBeenCalledTimes(2); + }); + + it('and conflicts were not resolved', async () => { + const { execSpy, promise, logSpy } = didResolveConflict(false); + expect.assertions(4); + + await promise.catch(e => { + expect(logSpy.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Backporting mySha to 6.x:", + ], + Array [ + "Please resolve conflicts in: /myHomeDir/.backport/repositories/elastic/kibana and when all conflicts have been resolved and staged run:", + ], + Array [ + " + git cherry-pick --continue + ", + ], + ] + `); + expect(e.message).toEqual('Aborted'); + expect(execSpy.mock.calls).toMatchSnapshot(); + expect(axiosMockInstance).toHaveBeenCalledTimes(0); + }); + }); }); }); diff --git a/yarn.lock b/yarn.lock index 8d9f06f7..2d7729bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -401,6 +401,13 @@ dependencies: "@types/lodash" "*" +"@types/lodash.last@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/lodash.last/-/lodash.last-3.0.6.tgz#7d616fa9bab00ff4398a883979a65d2711528148" + integrity sha512-7z2YKH0w6IAHieY1WGYCOkX8kkxYpgJr+H3dxK1tELJqSacFyAerc88UWXdh0Kr1EqM1RIuTJfP07MsRr8GCmw== + dependencies: + "@types/lodash" "*" + "@types/lodash@*": version "4.14.116" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.116.tgz#5ccf215653e3e8c786a58390751033a9adca0eb9"