From 3e0da4f0c2ddd7d341ecc13b8dba47da80c93dff Mon Sep 17 00:00:00 2001 From: Yuichi Sawada <4645011+yuichi10@users.noreply.github.com> Date: Sat, 9 Jun 2018 03:32:57 +0900 Subject: [PATCH] feat(1082): Implement getBranchList function (#91) --- index.js | 53 +++++++++++++++++++++++++++++++ package-lock.json | 56 ++++++++++++++++----------------- package.json | 2 +- test/index.test.js | 77 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 158 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index cb2d73b..3e6e9d6 100644 --- a/index.js +++ b/index.js @@ -20,6 +20,7 @@ const MATCH_COMPONENT_REPO_NAME = 3; const MATCH_COMPONENT_USER_NAME = 2; const MATCH_COMPONENT_HOST_NAME = 1; const WEBHOOK_PAGE_SIZE = 30; +const BRANCH_PAGE_SIZE = 100; const STATE_MAP = { SUCCESS: 'success', RUNNING: 'pending', @@ -915,6 +916,58 @@ class GithubScm extends Scm { return false; } } + + /** + * Look up a branches from a repo + * @async _findBranches + * @param {Object} config + * @param {Object} config.scmInfo Data about repo + * @param {String} config.token Admin token for repo + * @param {Number} config.page Pagination: page number to search next + * @return {Promise} Resolves to a list of branches + */ + async _findBranches(config) { + let branches = await this.breaker.runCommand({ + action: 'getBranches', + token: config.token, + params: { + owner: config.scmInfo.owner, + repo: config.scmInfo.repo, + page: config.page, + per_page: BRANCH_PAGE_SIZE + } + }); + + if (branches.length === BRANCH_PAGE_SIZE) { + config.page += 1; + const nextPageBranches = await this._findBranches(config); + + branches = branches.concat(nextPageBranches); + } + + return branches.map(branch => ({ name: hoek.reach(branch, 'name') })); + } + + /** + * Get branch list from the Github repository + * @async _getBranchList + * @param {Object} config + * @param {String} config.scmUri The SCM URI to get branch list + * @param {String} config.token Service token to authenticate with Github + * @return {Promise} Resolves when complete + */ + async _getBranchList(config) { + const scmInfo = await this.lookupScmUri({ + scmUri: config.scmUri, + token: config.token + }); + + return this._findBranches({ + scmInfo, + page: 1, + token: config.token + }); + } } module.exports = GithubScm; diff --git a/package-lock.json b/package-lock.json index f693b07..3bc03fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1159,16 +1159,16 @@ }, "isemail": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.2.tgz", + "resolved": "https://registry.npme.corp.yahoo.co.jp/i/isemail/_attachments/isemail-3.1.2.tgz", "integrity": "sha512-zfRhJn9rFSGhzU5tGZqepRSAj3+g6oTOHxMGGriWNJZzyLPUK8H7VHpqKntegnW8KLyGA9zwuNaCoopl40LTpg==", "requires": { - "punycode": "2.1.0" + "punycode": "2.1.1" }, "dependencies": { "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" + "version": "2.1.1", + "resolved": "https://registry.npme.corp.yahoo.co.jp/p/punycode/_attachments/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -1198,9 +1198,9 @@ } }, "joi": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.2.0.tgz", - "integrity": "sha512-VUzQwyCrmT2lIpxBCYq26dcK9veCQzDh84gQnCtaxCa8ePohX8JZVVsIb+E66kCUUcIvzeIpifa6eZuzqTZ3NA==", + "version": "13.4.0", + "resolved": "https://registry.npme.corp.yahoo.co.jp/j/joi/_attachments/joi-13.4.0.tgz", + "integrity": "sha512-JuK4GjEu6j7zr9FuVe2MAseZ6si/8/HaY0qMAejfDFHp7jcH4OKE937mIHM5VT4xDS0q7lpQbszbxKV9rm0yUg==", "requires": { "hoek": "5.0.3", "isemail": "3.1.2", @@ -3289,7 +3289,7 @@ "resolved": "https://registry.npmjs.org/retry-function/-/retry-function-2.1.0.tgz", "integrity": "sha512-yl8mfFg9N9nx3r01lCqY9+6oR4k/4zbmr9Vxke9lL/DwXtdkOC3fs1nVlBx1+/LQbJCwGG4tlc13JUVHfV7hsQ==", "requires": { - "joi": "13.2.0", + "joi": "13.4.0", "retry": "0.10.1" } }, @@ -3344,20 +3344,20 @@ "dev": true }, "screwdriver-data-schema": { - "version": "18.15.0", - "resolved": "https://registry.npmjs.org/screwdriver-data-schema/-/screwdriver-data-schema-18.15.0.tgz", - "integrity": "sha512-FCMLOTDzSvqnLNEZXkiuZj0McxkmsuCeeas8w/CWjmGPjou0s6Tku2FYNn7hoqyP7ALaas+kF25QgiPrcl4Q5g==", + "version": "18.24.2", + "resolved": "https://registry.npme.corp.yahoo.co.jp/s/screwdriver-data-schema/_attachments/screwdriver-data-schema-18.24.2.tgz", + "integrity": "sha512-rOy5lf+1rdx0JY7NETb1BralPd3oT8rWuaT2DmXtBce/SK8nMxcNYxauLtiejkoESwO6ypD9t1nt/CuppDn2Fw==", "requires": { - "joi": "13.2.0" + "joi": "13.4.0" } }, "screwdriver-scm-base": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/screwdriver-scm-base/-/screwdriver-scm-base-4.0.4.tgz", - "integrity": "sha512-CAUvFFQeksfe182K+1rogu2nK5gfm6pY0TPv68FnJzqZEN/+IQcJc4GUpBySKnROGHxxFyssthHneRFE8PdS+g==", + "version": "4.2.0", + "resolved": "https://registry.npme.corp.yahoo.co.jp/s/screwdriver-scm-base/_attachments/screwdriver-scm-base-4.2.0.tgz", + "integrity": "sha512-eZdsDnIAdqtz8D2OeZQyEuokw0aIb7XRfgNE4TAr6pvH8ChVJJ0mbYohyhGptlgG6vue0MQfLoT9EebLxLxyRg==", "requires": { - "joi": "13.2.0", - "screwdriver-data-schema": "18.15.0" + "joi": "13.4.0", + "screwdriver-data-schema": "18.24.2" } }, "semver": { @@ -3503,6 +3503,15 @@ "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==" }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -3513,15 +3522,6 @@ "strip-ansi": "4.0.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -3599,7 +3599,7 @@ }, "topo": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", + "resolved": "https://registry.npme.corp.yahoo.co.jp/t/topo/_attachments/topo-3.0.0.tgz", "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", "requires": { "hoek": "5.0.3" diff --git a/package.json b/package.json index 96c340e..0a16cdf 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "hoek": "^5.0.3", "joi": "^13.3.0", "screwdriver-data-schema": "^18.20.0", - "screwdriver-scm-base": "^4.1.0" + "screwdriver-scm-base": "^4.2.0" }, "release": { "debug": false, diff --git a/test/index.test.js b/test/index.test.js index e0ff39f..d566aaa 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -54,7 +54,8 @@ describe('index', function () { getById: sinon.stub(), getCommit: sinon.stub(), getContent: sinon.stub(), - getHooks: sinon.stub() + getHooks: sinon.stub(), + getBranches: sinon.stub() }, users: { getForUser: sinon.stub() @@ -1788,4 +1789,78 @@ jobs: }); }); }); + + describe('getBranchList', () => { + const branchListConfig = { + scmUri: 'github.com:1289:branchName', + token: 'fakeToken' + }; + + beforeEach(() => { + githubMock.repos.getById.yieldsAsync(null, { + full_name: 'dolores/violentdelights' + }); + githubMock.repos.getBranches.yieldsAsync(null, [{ + name: 'master', + commit: { + sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + url: 'https://api.github.com/repos/octocat/Hello-World/commits/c5b97' + }, + protected: true, + protection_url: 'https://api.github.com/protect' + }]); + }); + + it('gets branches', (done) => { + scm.getBranchList(branchListConfig).then((b) => { + assert.calledWith(githubMock.authenticate, sinon.match({ + token: 'fakeToken' + })); + assert.calledWith(githubMock.repos.getBranches, { + owner: 'dolores', + repo: 'violentdelights', + page: 1, + per_page: 100 + }); + assert.deepEqual(b, [{ name: 'master' }]); + done(); + }).catch(done); + }); + + it('gets a lot of branches', (done) => { + const fakeBranches = []; + + for (let i = 0; i < 300; i += 1) { + const bInfo = { + name: `master${i}`, + commit: { + sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + url: 'https://api.github.com/repos/octocat/Hello-World/commits/c5b97' + }, + protected: true, + protection_url: 'https://api.github.com/protect' + }; + + fakeBranches.push(bInfo); + } + githubMock.repos.getBranches.onCall(0).yieldsAsync(null, fakeBranches.slice(0, 100)); + githubMock.repos.getBranches.onCall(1).yieldsAsync(null, fakeBranches.slice(100, 200)); + githubMock.repos.getBranches.onCall(2).yieldsAsync(null, fakeBranches.slice(200, 300)); + githubMock.repos.getBranches.onCall(3).yieldsAsync(null, []); + scm.getBranchList(branchListConfig).then((branches) => { + assert.equal(branches.length, 300); + done(); + }).catch(done); + }); + + it('throws an error when failing to getBranches', () => { + const testError = new Error('getBranchesError'); + + githubMock.repos.getBranches.yieldsAsync(testError); + + return scm.getBranchList(branchListConfig).then(assert.fail, (err) => { + assert.equal(err, testError); + }); + }); + }); });