From f559934f1dd20e47f43a95e97d33cfe7736e5bf0 Mon Sep 17 00:00:00 2001 From: Avi Haiat Date: Mon, 27 Jun 2016 16:52:16 +0300 Subject: [PATCH] feat(app): Add retry when publishing version to github --- bin/mcfly-semantic-release.js | 10 ++- lib/retryHelper.js | 21 ++++++ package.json | 115 +++++++++++++++++---------------- test/mocha/retryHelper.spec.js | 84 ++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 58 deletions(-) create mode 100644 lib/retryHelper.js create mode 100644 test/mocha/retryHelper.spec.js diff --git a/bin/mcfly-semantic-release.js b/bin/mcfly-semantic-release.js index c042d20..7da05ed 100644 --- a/bin/mcfly-semantic-release.js +++ b/bin/mcfly-semantic-release.js @@ -6,6 +6,7 @@ global.Promise = require('bluebird'); const args = require('yargs').argv; const chalk = require('chalk'); const changelogScript = require('../lib/changelog-script'); +const retryHelper = require('../lib/retryHelper'); const gitHelper = require('../lib/githelper'); const githubHelper = require('mcfly-github'); const inquirer = require('inquirer'); @@ -110,7 +111,14 @@ gitHelper.getCurrentBranch() .delay(1000) .then((msg) => { console.log(chalk.yellow('Publishing version...')); - return githubHelper.createRelease(msg); + return retryHelper.retry(function() { + githubHelper.createRelease(msg); + }) + .catch(err => { + console.log(chalk.red('An error occurred when publishing the version')); + console.log('Your changelog is:\n', msg.changelogContent); + throw err; + }); }) .then((res) => { console.log(chalk.green(`Release ${res.name} successfully published!`)); diff --git a/lib/retryHelper.js b/lib/retryHelper.js new file mode 100644 index 0000000..cc90215 --- /dev/null +++ b/lib/retryHelper.js @@ -0,0 +1,21 @@ +'use strict'; +var retry = require('bluebird-retry'); + +/** + * Retries with default options + * @param {Function} fn The function to retry (should return promise) + * @param {Object} [opts] The options for the retry (optional) + * @returns {Promise} The result as a resolved or rejected promise + */ +var retryFn = function(fn, opts) { + opts = opts || { + max_tries: 3, + interval: 500, + backoff: 2 + }; + return retry(fn, opts); +}; + +module.exports = { + retry: retryFn +}; diff --git a/package.json b/package.json index a15a765..2505035 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,59 @@ { - "name": "mcfly-semantic-release", - "version": "1.0.11", - "description": "A cli tool to bump version and publish to github", - "bin": { - "mcfly-semantic-release": "./bin/mcfly-semantic-release.js" - }, - "dependencies": { - "bluebird": "^3.4.0", - "chalk": "^1.1.3", - "inquirer": "^1.0.3", - "lodash": "4.13.1", - "mcfly-github": "^1.0.2", - "memory-stream": "0.0.3", - "node-jsxml": "^0.7.0", - "semver": "^5.1.0", - "simple-git": "^1.38.0", - "strip-json-comments": "^2.0.1", - "yargs": "^4.7.1" - }, - "devDependencies": { - "chai": "^3.5.0", - "coveralls": "^2.11.9", - "eslint": "^2.13.1", - "eslint-plugin-json": "^1.2.0", - "eslint-plugin-nodeca": "^1.0.3", - "istanbul": "^0.4.4", - "mocha": "^2.5.3", - "sinon": "^1.17.4", - "sinon-chai": "^2.8.0" - }, - "scripts": { - "eslint": "eslint .", - "lint": "npm run eslint", - "pretest": "npm run eslint", - "test": "npm run mocha", - "mocha": "istanbul cover --root . --include-all-sources -x **/coverage/** -x **/client/** -x **/files/** -x **/node_modules/** -x **/bin/** --dir ./coverage/mocha --report text --report text-summary --report lcov --print none _mocha -- test/mocha/**/*.spec.js --reporter spec --timeout 10000", - "mocha:watch": "mocha test/mocha/**/*.spec.js -R nyan -w --timeout 10000", - "release": "node bin/mcfly-semantic-release.js" - }, - "files": [ - "lib", - "bin" - ], - "engines": { - "node": ">= 4.2.1 < 5" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/mcfly-io/mcfly-semantic-release.git" - }, - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/mcfly-io/mcfly-semantic-release/issues" - }, - "homepage": "https://github.com/mcfly-io/mcfly-semantic-release#readme" -} \ No newline at end of file + "name": "mcfly-semantic-release", + "version": "1.0.11", + "description": "A cli tool to bump version and publish to github", + "bin": { + "mcfly-semantic-release": "./bin/mcfly-semantic-release.js" + }, + "dependencies": { + "bluebird": "^3.4.0", + "bluebird-retry": "^0.7.0", + "chalk": "^1.1.3", + "inquirer": "^1.1.0", + "lodash": "4.13.1", + "mcfly-github": "^1.0.5", + "memory-stream": "0.0.3", + "node-jsxml": "^0.7.0", + "semver": "^5.1.1", + "simple-git": "^1.38.0", + "strip-json-comments": "^2.0.1", + "yargs": "^4.7.1" + }, + "devDependencies": { + "chai": "^3.5.0", + "coveralls": "^2.11.9", + "eslint": "^2.13.1", + "eslint-plugin-json": "^1.2.0", + "eslint-plugin-nodeca": "^1.0.3", + "istanbul": "^0.4.4", + "mocha": "^2.5.3", + "sinon": "^1.17.4", + "sinon-chai": "^2.8.0" + }, + "scripts": { + "eslint": "eslint .", + "lint": "npm run eslint", + "pretest": "npm run eslint", + "test": "npm run mocha", + "mocha": "istanbul cover --root . --include-all-sources -x **/coverage/** -x **/client/** -x **/files/** -x **/node_modules/** -x **/bin/** --dir ./coverage/mocha --report text --report text-summary --report lcov --print none _mocha -- test/mocha/**/*.spec.js --reporter spec --timeout 10000", + "mocha:watch": "mocha test/mocha/**/*.spec.js -R nyan -w --timeout 10000", + "release": "node bin/mcfly-semantic-release.js" + }, + "files": [ + "lib", + "bin" + ], + "engines": { + "node": ">= 4.2.1 < 5" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/mcfly-io/mcfly-semantic-release.git" + }, + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/mcfly-io/mcfly-semantic-release/issues" + }, + "homepage": "https://github.com/mcfly-io/mcfly-semantic-release#readme" +} diff --git a/test/mocha/retryHelper.spec.js b/test/mocha/retryHelper.spec.js new file mode 100644 index 0000000..1763344 --- /dev/null +++ b/test/mocha/retryHelper.spec.js @@ -0,0 +1,84 @@ +'use strict'; + +var retryHelper = require('../../lib/retryHelper'); +var chai = require('chai'); +var expect = chai.expect; +var sinon = require('sinon'); +var sinonChai = require('sinon-chai'); +chai.use(sinonChai); + +var mockPromise = sinon.spy(function(obj) { + return new Promise((resolve, reject) => { + obj.count++; + if (obj.count < 3) { + reject(new Error('an error occurred')); + } else { + resolve(obj); + } + }); +}); + +describe('retryHelper', () => { + describe('retry()', () => { + beforeEach(function() { + mockPromise.reset(); + }); + + it('with standard option should succeed', done => { + var obj = { + count: 0 + }; + retryHelper.retry(function() { + return mockPromise(obj); + }) + .then(obj => { + expect(mockPromise).to.have.callCount(3); + expect(obj.count).to.equal(3); + done(); + }) + .catch(done); + }); + + it('with standard option should fail after 3 tries', done => { + var obj = { + count: -1 + }; + retryHelper.retry(function() { + return mockPromise(obj); + }, { + max_tries: 3, + interval: 1, + backoff: 1 + }) + .then(obj => { + done(new Error('should throw an error')); + }) + .catch(err => { + + expect(mockPromise).to.have.callCount(3); + expect(obj.count).to.equal(2); + done(); + }); + }); + + it('with specific option should succeed', done => { + var obj = { + count: -1 + }; + retryHelper.retry(function() { + return mockPromise(obj); + }, { + max_tries: 4, + interval: 1, + backoff: 1 + }) + .then(obj => { + expect(mockPromise).to.have.callCount(4); + expect(obj.count).to.equal(3); + done(); + }) + .catch(done); + }); + }); + +});