From bd7c38481c36edc451a01810edbd70f15f6cf033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 30 Oct 2017 00:20:47 +0100 Subject: [PATCH 1/4] Add PR label --- .vscode/launch.json | 2 +- src/cli.js | 16 ++++--- src/cliService.js | 92 +++++++++++++++++------------------- src/configs.js | 5 ++ src/git.js | 5 -- src/github.js | 10 ++++ src/prompts.js | 102 ++++++++++++++++++++++------------------ test/cliService.test.js | 52 +++++++++++++------- 8 files changed, 161 insertions(+), 123 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3d564342..254bb712 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ { "type": "node", "request": "launch", - "name": "Launch Program", + "name": "Run file", "program": "${file}" }, { diff --git a/src/cli.js b/src/cli.js index 73bbf0af..b3b24f3d 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,5 +1,9 @@ const github = require('./github'); -const { ensureConfigAndFoldersExists, validateConfig } = require('./configs'); +const { + ensureConfigAndFoldersExists, + validateConfig, + getRepoConfig +} = require('./configs'); const { promptRepoInfo, promptCommit, @@ -11,7 +15,7 @@ const { } = require('./cliService'); function init(config, options) { - let commit, versions, reference, owner, repoName; + let commit, versions, reference, owner, repoName, repoConfig; return ensureConfigAndFoldersExists() .then(() => validateConfig(config)) @@ -20,14 +24,13 @@ function init(config, options) { .then(({ owner: _owner, repoName: _repoName }) => { owner = _owner; repoName = _repoName; + repoConfig = getRepoConfig(owner, repoName, config.repositories); }) .then(() => promptCommit(owner, repoName, options.own ? config.username : null) ) .then(c => (commit = c)) - .then(() => - promptVersions(owner, repoName, config.repositories, options.multiple) - ) + .then(() => promptVersions(repoConfig.versions, options.multiple)) .then(v => (versions = v)) .then(() => getReference(owner, repoName, commit.sha)) .then(ref => (reference = ref)) @@ -39,7 +42,8 @@ function init(config, options) { commit, reference, versions, - username: config.username + username: config.username, + labels: repoConfig.labels }) ) .catch(handleErrors); diff --git a/src/cliService.js b/src/cliService.js index 6d409a10..a30d0f90 100644 --- a/src/cliService.js +++ b/src/cliService.js @@ -15,13 +15,6 @@ const { setupRepo } = require('./git'); -function sequentially(items, handler) { - return items.reduce( - (p, item) => p.then(() => handler(item)), - Promise.resolve() - ); -} - const service = {}; service.doBackportVersions = ({ owner, @@ -29,7 +22,8 @@ service.doBackportVersions = ({ commit, reference, versions, - username + username, + labels }) => { return sequentially(versions, version => { return service @@ -39,7 +33,8 @@ service.doBackportVersions = ({ commit, reference, version, - username + username, + labels }) .then(res => console.log(`View pull request: ${res.data.html_url}\n`)) .catch(service.handleErrors); @@ -52,13 +47,12 @@ service.doBackportVersion = ({ commit, reference, version, - username + username, + labels = [] }) => { const backportBranchName = getBackportBranchName(version, reference); - console.log( - `Backporting ${service.getReferenceValue(reference)} to ${version}` - ); + console.log(`Backporting ${getReferenceLong(reference)} to ${version}`); return withSpinner( resetAndPullMaster(owner, repoName).then(() => @@ -81,7 +75,14 @@ service.doBackportVersion = ({ username ); return withSpinner( - github.createPullRequest(owner, repoName, payload), + github.createPullRequest(owner, repoName, payload).then(res => { + if (labels.length > 0) { + return github + .addLabels(owner, repoName, res.data.number, labels) + .then(() => res); + } + return res; + }), 'Creating pull request' ); }); @@ -108,9 +109,7 @@ service.promptRepoInfo = (repositories, cwd) => { console.log(`Repository: ${currentFullRepoName}`); return currentFullRepoName; } - return prompts - .listFullRepoName(fullRepoNames) - .then(({ fullRepoName }) => fullRepoName); + return prompts.listFullRepoName(fullRepoNames); }) .then(fullRepoName => { const [owner, repoName] = fullRepoName.split('/'); @@ -140,22 +139,13 @@ service.promptCommit = (owner, repoName, username) => { .then(commits => { spinner.stop(); return prompts.listCommits(commits); - }) - .then(({ commit }) => commit); + }); }; -service.promptVersions = ( - owner, - repoName, - repositories, - multipleChoice = false -) => { - const versions = getVersions(owner, repoName, repositories); - if (multipleChoice) { - return prompts.checkboxVersions(versions).then(({ versions }) => versions); - } - - return prompts.listVersions(versions).then(({ version }) => [version]); +service.promptVersions = (versions, multipleChoice = false) => { + return multipleChoice + ? prompts.checkboxVersions(versions) + : prompts.listVersions(versions); }; service.handleErrors = e => { @@ -207,15 +197,27 @@ service.handleErrors = e => { } }; -service.getReferenceValue = reference => { - return reference.type === 'pullRequest' - ? `pull request #${reference.value}` - : `commit ${reference.value}`; -}; +function sequentially(items, handler) { + return items.reduce( + (p, item) => p.then(() => handler(item)), + Promise.resolve() + ); +} -function getVersions(owner, repoName, repositories) { - return repositories.find(repo => repo.name === `${owner}/${repoName}`) - .versions; +function getReferenceValue({ type, value }, { short }) { + if (type === 'pullRequest') { + return short ? `pr-${value}` : `pull request #${value}`; + } + + return short ? `commit-${value}` : `commit ${value}`; +} + +function getReferenceLong(reference) { + return getReferenceValue(reference, { short: false }); +} + +function getReferenceShort(reference) { + return getReferenceValue(reference, { short: true }); } function isCherrypickConflict(e) { @@ -235,7 +237,7 @@ function cherrypickAndPrompt(owner, repoName, sha) { throw e; } - return prompts.confirmConflictResolved().then(({ isConflictResolved }) => { + return prompts.confirmConflictResolved().then(isConflictResolved => { if (!isConflictResolved) { const error = new Error(constants.CHERRYPICK_CONFLICT_NOT_HANDLED); error.details = e.message; @@ -246,16 +248,10 @@ function cherrypickAndPrompt(owner, repoName, sha) { } function getBackportBranchName(version, reference) { - const refValue = getReferenceValueShort(reference); + const refValue = getReferenceShort(reference); return `backport/${version}/${refValue}`; } -function getReferenceValueShort(reference) { - return reference.type === 'pullRequest' - ? `pr-${reference.value}` - : `commit-${reference.value}`; -} - function getCurrentFullRepoName(fullRepoNames, cwd) { const currentDir = path.basename(cwd); return fullRepoNames.find(name => name.endsWith(`/${currentDir}`)); @@ -263,7 +259,7 @@ function getCurrentFullRepoName(fullRepoNames, cwd) { function getPullRequestPayload(commitMessage, version, reference, username) { const backportBranchName = getBackportBranchName(version, reference); - const refValue = service.getReferenceValue(reference); + const refValue = getReferenceLong(reference); return { title: `[${version}] ${commitMessage}`, diff --git a/src/configs.js b/src/configs.js index a6184e8f..feb71b49 100644 --- a/src/configs.js +++ b/src/configs.js @@ -27,6 +27,10 @@ function ensureConfigAndFoldersExists() { }); } +function getRepoConfig(owner, repoName, repositories) { + return repositories.find(repo => repo.name === `${owner}/${repoName}`); +} + function getConfigTemplate() { return utils.readFile(path.join(__dirname, 'configTemplate.json'), 'utf8'); } @@ -63,5 +67,6 @@ function getConfig() { module.exports = { ensureConfigAndFoldersExists, getConfig, + getRepoConfig, validateConfig }; diff --git a/src/git.js b/src/git.js index 17651a81..9ce5c0ab 100644 --- a/src/git.js +++ b/src/git.js @@ -79,16 +79,11 @@ function resetAndPullMaster(owner, repoName) { ); } -function getCommit(repo, sha) { - return repo.getCommit(sha); -} - module.exports = { resetAndPullMaster, cherrypick, cloneRepo, createAndCheckoutBranch, - getCommit, repoExists, setupRepo, push diff --git a/src/github.js b/src/github.js index d9f584f5..0b7f27ec 100644 --- a/src/github.js +++ b/src/github.js @@ -55,6 +55,15 @@ function createPullRequest(owner, repoName, payload) { .catch(throwGithubError); } +function addLabels(owner, repoName, pullNumber, labels) { + return axios + .post( + `https://api.github.com/repos/${owner}/${repoName}/issues/${pullNumber}/labels?access_token=${accessToken}`, + labels + ) + .catch(throwGithubError); +} + function getPullRequestByCommit(owner, repoName, commitSha) { return axios( `https://api.github.com/search/issues?q=repo:${owner}/${repoName}+${commitSha}&access_token=${accessToken}` @@ -69,6 +78,7 @@ function setAccessToken(_accessToken) { module.exports = { setAccessToken, + addLabels, createPullRequest, getCommits, getPullRequestByCommit diff --git a/src/prompts.js b/src/prompts.js index 32f5f9a4..cedcf73a 100644 --- a/src/prompts.js +++ b/src/prompts.js @@ -1,66 +1,76 @@ const inquirer = require('inquirer'); function listFullRepoName(repoNames) { - return inquirer.prompt([ - { - type: 'list', - name: 'fullRepoName', - message: 'Select repository', - choices: repoNames - } - ]); + return inquirer + .prompt([ + { + type: 'list', + name: 'fullRepoName', + message: 'Select repository', + choices: repoNames + } + ]) + .then(({ fullRepoName }) => fullRepoName); } function listCommits(commits) { const pageSize = Math.min(10, commits.length); - return inquirer.prompt([ - { - pageSize, - type: 'list', - name: 'commit', - message: 'Select commit to backport', - choices: commits - .map(commit => ({ - name: commit.message, - value: commit, - short: commit.message - })) - .concat(commits.length > pageSize ? new inquirer.Separator() : []) - } - ]); + return inquirer + .prompt([ + { + pageSize, + type: 'list', + name: 'commit', + message: 'Select commit to backport', + choices: commits + .map(commit => ({ + name: commit.message, + value: commit, + short: commit.message + })) + .concat(commits.length > pageSize ? new inquirer.Separator() : []) + } + ]) + .then(({ commit }) => commit); } function listVersions(versions) { - return inquirer.prompt([ - { - type: 'list', - name: 'version', - message: 'Select version to backport to', - choices: versions - } - ]); + return inquirer + .prompt([ + { + type: 'list', + name: 'version', + message: 'Select version to backport to', + choices: versions + } + ]) + .then(({ version }) => [version]); } function checkboxVersions(versions) { - return inquirer.prompt([ - { - type: 'checkbox', - name: 'versions', - message: 'Select version to backport to', - choices: versions - } - ]); + return inquirer + .prompt([ + { + type: 'checkbox', + name: 'versions', + message: 'Select version to backport to', + choices: versions + } + ]) + .then(({ versions }) => versions); } function confirmConflictResolved() { - return inquirer.prompt([ - { - type: 'confirm', - name: 'isConflictResolved', - message: 'Have you solved the merge conflict?' - } - ]); + return inquirer + .prompt([ + { + type: 'confirm', + name: 'isConflictResolved', + message: 'Have you solved the merge conflict?' + } + ]) + .then(({ isConflictResolved }) => isConflictResolved); } module.exports = { diff --git a/test/cliService.test.js b/test/cliService.test.js index 32a4d7f5..1d3d9b2d 100644 --- a/test/cliService.test.js +++ b/test/cliService.test.js @@ -13,15 +13,27 @@ describe('doBackportVersion', () => { beforeEach(() => { mockBackportDirPath(); utils.exec = jest.fn().mockReturnValue(Promise.resolve()); - nock('https://api.github.com') - .post(`/repos/elastic/kibana/pulls`) + + this.addLabelMock = nock('https://api.github.com') + .post(`/repos/elastic/kibana/issues/1337/labels`, ['backport']) + .query(true) + .reply(200, {}); + }); + + it('with pull request reference', () => { + this.createPRMock = nock('https://api.github.com') + .post(`/repos/elastic/kibana/pulls`, { + title: '[6.x] myCommitMessage', + body: 'Backports pull request #myPullRequest to 6.x', + head: 'sqren:backport/6.x/pr-myPullRequest', + base: '6.x' + }) .query(true) .reply(200, { + number: 1337, html_url: 'myHtmlUrl' }); - }); - it('with pull request reference', () => { return cliService .doBackportVersion({ owner: 'elastic', @@ -29,21 +41,31 @@ describe('doBackportVersion', () => { commit: { message: 'myCommitMessage' }, reference: { type: 'pullRequest', value: 'myPullRequest' }, version: '6.x', - username: 'sqren' + username: 'sqren', + labels: ['backport'] }) .then(res => { - expect(JSON.parse(res.config.data)).toEqual({ - base: '6.x', - body: 'Backports pull request #myPullRequest to 6.x', - head: 'sqren:backport/6.x/pr-myPullRequest', - title: '[6.x] myCommitMessage' - }); expect(res.config).toMatchSnapshot(); expect(utils.exec.mock.calls).toMatchSnapshot(); + expect(this.createPRMock.isDone()).toBe(true); + expect(this.addLabelMock.isDone()).toBe(true); }); }); it('with commit reference', () => { + this.createPRMock = nock('https://api.github.com') + .post(`/repos/elastic/kibana/pulls`, { + title: '[6.x] myCommitMessage', + body: 'Backports commit myCommitSha to 6.x', + head: 'sqren:backport/6.x/commit-myCommitSha', + base: '6.x' + }) + .query(true) + .reply(200, { + number: 1337, + html_url: 'myHtmlUrl' + }); + return cliService .doBackportVersion({ owner: 'elastic', @@ -54,14 +76,10 @@ describe('doBackportVersion', () => { username: 'sqren' }) .then(res => { - expect(JSON.parse(res.config.data)).toEqual({ - base: '6.x', - body: 'Backports commit myCommitSha to 6.x', - head: 'sqren:backport/6.x/commit-myCommitSha', - title: '[6.x] myCommitMessage' - }); expect(res.config).toMatchSnapshot(); expect(utils.exec.mock.calls).toMatchSnapshot(); + expect(this.createPRMock.isDone()).toBe(true); + expect(this.addLabelMock.isDone()).toBe(false); }); }); }); From 7d58135fb8d2c45f3ce3443c22791b6c2d601f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 30 Oct 2017 08:40:10 +0100 Subject: [PATCH 2/4] Updated readme --- readme.MD | 6 ++++-- src/configTemplate.json | 6 ++++-- test/__snapshots__/cli.test.js.snap | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/readme.MD b/readme.MD index 695b6470..cea5d055 100644 --- a/readme.MD +++ b/readme.MD @@ -45,11 +45,13 @@ You need to update the config file with your Github username and a Github Access "repositories": [ { "name": "elastic/x-pack-kibana", - "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"] + "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"], + "labels": ["backport"] }, { "name": "elastic/kibana", - "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"] + "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"], + "labels": ["backport"] } ] } diff --git a/src/configTemplate.json b/src/configTemplate.json index 817c95a2..dac88f47 100644 --- a/src/configTemplate.json +++ b/src/configTemplate.json @@ -16,11 +16,13 @@ "repositories": [ { "name": "elastic/x-pack-kibana", - "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"] + "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"], + "labels": ["backport"] }, { "name": "elastic/kibana", - "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"] + "versions": ["6.x", "6.0", "5.6", "5.5", "5.4"], + "labels": ["backport"] } ] } diff --git a/test/__snapshots__/cli.test.js.snap b/test/__snapshots__/cli.test.js.snap index 6e47e36c..acd146c1 100644 --- a/test/__snapshots__/cli.test.js.snap +++ b/test/__snapshots__/cli.test.js.snap @@ -135,11 +135,13 @@ Array [ \\"repositories\\": [ { \\"name\\": \\"elastic/x-pack-kibana\\", - \\"versions\\": [\\"6.x\\", \\"6.0\\", \\"5.6\\", \\"5.5\\", \\"5.4\\"] + \\"versions\\": [\\"6.x\\", \\"6.0\\", \\"5.6\\", \\"5.5\\", \\"5.4\\"], + \\"labels\\": [\\"backport\\"] }, { \\"name\\": \\"elastic/kibana\\", - \\"versions\\": [\\"6.x\\", \\"6.0\\", \\"5.6\\", \\"5.5\\", \\"5.4\\"] + \\"versions\\": [\\"6.x\\", \\"6.0\\", \\"5.6\\", \\"5.5\\", \\"5.4\\"], + \\"labels\\": [\\"backport\\"] } ] } From 44cb573c46d46e13ad96f133969b0140c9442930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 30 Oct 2017 21:33:59 +0100 Subject: [PATCH 3/4] 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2e043a2e..5297b964 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "backport", - "version": "1.0.1", + "version": "1.1.0", "main": "./src/index.js", "bin": { "backport": "./src/index.js" From 17397108b00c0ac269df7c5ed84996af70891c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 30 Oct 2017 21:37:23 +0100 Subject: [PATCH 4/4] Run ESLint on Travis --- .travis.yml | 3 +++ package.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6eb28acf..8ca711aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,6 @@ node_js: - "6" - "8" cache: yarn +script: + - npm run lint + - npm test diff --git a/package.json b/package.json index 5297b964..d61ba1d9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ }, "license": "MIT", "scripts": { - "test": "jest" + "test": "jest", + "lint": "eslint ./src" }, "repository": { "type": "git",