From a4cca141de7dfe3f101f020e9146c966a0742cba Mon Sep 17 00:00:00 2001 From: Alex Canessa Date: Thu, 9 Mar 2017 19:49:05 +0000 Subject: [PATCH] Refactor promises (#33) * Require github-release-notes.js in the bin file * Catch promises errors and handle them in a new way * Update github-api and remove is-online from package.json * Add hasNetwork check back in * Update the changelog * Kill all tasks when catching an error * Remove extra line in the changelog * Revert connectivity check --- bin/gren.js | 12 +-- github-release-notes.js | 5 + package.json | 3 +- src/gren.js | 215 ++++++++++++++++------------------------ src/utils.js | 34 ++++++- 5 files changed, 120 insertions(+), 149 deletions(-) diff --git a/bin/gren.js b/bin/gren.js index 83c896c3..6f0136ea 100644 --- a/bin/gren.js +++ b/bin/gren.js @@ -1,13 +1,3 @@ #!/usr/bin/env node -'use strict'; - -var GithubReleaseNotes = require('./src/gren'); -var gren = new GithubReleaseNotes(); -var utils = require('./src/utils'); -var action = utils.getBashOptions(process.argv)['action']; - -gren.init() - .then(function() { - return gren[action || 'release'](); - }); +require('../github-release-notes'); diff --git a/github-release-notes.js b/github-release-notes.js index 83a21366..1010a590 100644 --- a/github-release-notes.js +++ b/github-release-notes.js @@ -8,4 +8,9 @@ var action = utils.getBashOptions(process.argv)['action']; gren.init() .then(function() { return gren[action || 'release'](); + }) + .catch(function(error) { + utils.clearTasks(gren); + + console.error(error); }); diff --git a/package.json b/package.json index bfc9fcd9..0a9ea52b 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,7 @@ "chalk": "^1.1.3", "connectivity": "^1.0.0", "es6-promise": "^3.2.1", - "github-api": "^2.1.0", - "is-online": "^5.1.1", + "github-api": "^3.0.0", "object-assign": "^4.1.0" }, "devDependencies": { diff --git a/src/gren.js b/src/gren.js index 0b8a72ec..7da44f0d 100644 --- a/src/gren.js +++ b/src/gren.js @@ -45,21 +45,18 @@ var defaults = { * @return {Promise} */ function editRelease(gren, releaseId, releaseOptions) { - var loaded = utils.task('Updating latest release'); + var loaded = utils.task(gren, 'Updating latest release'); - return new Promise(function(resolve, reject) { - gren.repo.updateRelease(releaseId, releaseOptions, function(err, release) { + return gren.repo.updateRelease(releaseId, releaseOptions) + .then(function(response) { loaded(); - if (err) { - reject(chalk.red(err)); - } else { - console.log(chalk.green('\n\n' + release.name + ' has been successfully updated!')); + var release = response.data; - resolve(true); - } + console.log(chalk.green('\n\n' + release.name + ' has been successfully updated!')); + + return release; }); - }); } /** @@ -71,7 +68,7 @@ function editRelease(gren, releaseId, releaseOptions) { * @param {GithubReleaseNotes} gren The gren object * @param {Object} releaseOptions The options to build the release: * @example { - * "tag_name": "v1.0.0", + * "tag_name": "1.0.0", * "target_commitish": "master", * "name": "v1.0.0", * "body": "Description of the release", @@ -82,26 +79,17 @@ function editRelease(gren, releaseId, releaseOptions) { * @return {Promise} */ function createRelease(gren, releaseOptions) { - var loaded = utils.task('Preparing the release'); + var loaded = utils.task(gren, 'Preparing the release'); - return new Promise(function(resolve, reject) { - gren.repo.createRelease(releaseOptions, function(err, release) { + return gren.repo.createRelease(releaseOptions) + .then(function(response) { loaded(); + var release = response.data; - if (err) { - var responseText = JSON.parse(err.request.responseText); - console.log(chalk.red( - responseText.message + '\n' + - responseText.errors[0].code - )); - reject(false); - } else { - console.log(chalk.green('\n\n' + release.name + ' has been successfully created!')); - - resolve(true); - } + console.log(chalk.green('\n\n' + release.name + ' has been successfully created!')); + + return release; }); - }); } /** @@ -118,7 +106,7 @@ function createRelease(gren, releaseOptions) { function prepareRelease(gren, block) { var releaseOptions = { tag_name: block.release, - name: gren.options.prefix + block.release, + name: block.name, body: block.body, draft: gren.options.draft, prerelease: gren.options.prerelease @@ -126,9 +114,9 @@ function prepareRelease(gren, block) { if (block.id) { return editRelease(gren, block.id, releaseOptions); - } else { - return createRelease(gren, releaseOptions); } + + return createRelease(gren, releaseOptions); } /** @@ -171,41 +159,36 @@ function getSelectedTags(optionTags, tags) { * @return {Promise} */ function getLastTags(gren, releases) { - var loaded = utils.task('Getting tags'); + var loaded = utils.task(gren, 'Getting tags'); - return new Promise(function(resolve, reject) { - gren.repo.listTags(function(err, tags) { + return gren.repo.listTags() + .then(function(response) { loaded(); - if (err) { - reject(err); - } else { - var filteredTags = - (getSelectedTags(gren.options.tags, tags) || [tags[0], tags[1]]) - .map(function(tag) { - var tagRelease = releases && releases.filter(function(release) { - return release.tag_name === tag.name; - })[0] || false; - var releaseId = tagRelease ? tagRelease.id : null; - - return { - tag: tag, - releaseId: releaseId - }; - }); - - if (filteredTags[0].releaseId && !gren.options.override) { - reject(chalk.red(filteredTags[0].tag.name + ' is a release, use --override flag to override an existing release!')); - } + var tags = response.data; + var filteredTags = (getSelectedTags(gren.options.tags, tags) || [tags[0], tags[1]]) + .map(function(tag) { + var tagRelease = releases && releases.filter(function(release) { + return release.tag_name === tag.name; + })[0] || false; + var releaseId = tagRelease ? tagRelease.id : null; - console.log('Tags found: ' + filteredTags.map(function(tag) { - return tag.tag.name; - }).join(', ')); + return { + tag: tag, + releaseId: releaseId + }; + }); - resolve(filteredTags); + if (filteredTags[0].releaseId && !gren.options.override) { + throw chalk.red(filteredTags[0].tag.name + ' is a release, use --override flag to override an existing release!'); } + + console.log('Tags found: ' + filteredTags.map(function(tag) { + return tag.tag.name; + }).join(', ')); + + return filteredTags; }); - }); } /** @@ -221,19 +204,14 @@ function getLastTags(gren, releases) { */ function getTagDates(gren, tags) { return tags.map(function(tag) { - return new Promise(function(resolve, reject) { - gren.repo.getCommit(tag.tag.commit.sha, function(err, commit) { - if (err) { - reject(err); - } else { - resolve({ - id: tag.releaseId, - name: tag.tag.name, - date: commit.committer.date - }); - } + return gren.repo.getCommit(tag.tag.commit.sha) + .then(function(response) { + return { + id: tag.releaseId, + name: tag.tag.name, + date: response.data.committer.date + }; }); - }); }); } @@ -270,24 +248,18 @@ function getReleaseDates(gren, releases) { * @return {Promise} The promise which resolves an array of releases */ function getListReleases(gren) { - var loaded = utils.task('Getting the list of releases'); + var loaded = utils.task(gren, 'Getting the list of releases'); - return new Promise(function(resolve, reject) { - gren.repo.listReleases(function(err, releases) { + return gren.repo.listReleases() + .then(function(response) { loaded(); - if (err && err.request.status !== 404) { - reject(err); - } else { - if (err && err.request.status === 404) { - resolve(false); - } else { - process.stdout.write(releases.length + ' releases found\n'); - resolve(releases); - } - } + var releases = response.data; + + process.stdout.write(releases.length + ' releases found\n'); + + return releases; }); - }); } /** @@ -335,7 +307,7 @@ function templateLabels(issue) { return issue.labels ? issue.labels.map(function(label) { return '[**' + label.name + '**] '; }) - .join('') : '[closed]'; + .join('') : '[closed]'; } /** @@ -351,7 +323,7 @@ function templateLabels(issue) { function templateBlock(block) { var date = new Date(block.date); - return '## ' + block.release + ' (' + utils.formatDate(date) + ')' + '\n\n' + + return '## ' + block.name + ' (' + utils.formatDate(date) + ')' + '\n\n' + block.body; } @@ -382,8 +354,8 @@ function templateIssue(issue) { function templateChangelog(blocks) { return '# Changelog\n\n' + blocks - .map(templateBlock) - .join('\n\n --- \n\n'); + .map(templateBlock) + .join('\n\n --- \n\n'); } /** @@ -397,7 +369,7 @@ function templateChangelog(blocks) { * @return {string} */ function templateIssueBody(body, rangeBody) { - return (body ? body.join('\n') : rangeBody || '*No changelog for this release.*') + '\n'; + return (body.length ? body.join('\n') : rangeBody || '*No changelog for this release.*') + '\n'; } /** @@ -474,15 +446,10 @@ function getCommitsBetweenTwo(gren, since, until) { per_page: 100 }; - return new Promise(function(resolve, reject) { - gren.repo.listCommits(options, function(err, commits) { - if (err) { - reject(err); - } else { - resolve(commitMessages(commits)); - } + return gren.repo.listCommits(options) + .then(function(commits) { + return commitMessages(commits); }); - }); } /** @@ -527,28 +494,23 @@ function getCommitBlocks(gren, releaseRanges) { * @return {Promise} The promise which resolves the list of the issues */ function getClosedIssues(gren, releaseRanges) { - var loaded = utils.task('Getting all closed issues'); + var loaded = utils.task(gren, 'Getting all closed issues'); - return new Promise(function(resolve, reject) { - gren.issues.listIssues({ - state: 'closed', - since: releaseRanges[0][1].date - }, function(err, issues) { + return gren.issues.listIssues({ + state: 'closed', + since: releaseRanges[0][1].date + }) + .then(function(response) { loaded(); - if (err) { - reject(err); - } else { - var filteredIssues = issues.filter(function(issue) { - return !issue.pull_request; - }); + var filteredIssues = response.data.filter(function(issue) { + return !issue.pull_request; + }); - process.stdout.write(filteredIssues.length + ' issues found\n'); + process.stdout.write(filteredIssues.length + ' issues found\n'); - resolve(filteredIssues); - } + return filteredIssues; }); - }); } /** @@ -563,7 +525,7 @@ function getClosedIssues(gren, releaseRanges) { * @return {Promise[]} */ function getIssueBlocks(gren, releaseRanges) { - console.log('\nCreating the body blocks from issues:'); + console.log('\nCreating the body blocks from releases:'); return getClosedIssues(gren, releaseRanges) .then(function(issues) { @@ -582,6 +544,7 @@ function getIssueBlocks(gren, releaseRanges) { return { id: range[0].id, release: range[0].name, + name: gren.options.prefix + range[0].name, date: range[0].date, body: templateIssueBody(body, range[0].body) }; @@ -752,9 +715,11 @@ function hasNetwork() { connectivity(function(isOnline) { if (!isOnline) { reject(chalk.red('You need to have network connectivity')); + + return; } - resolve(isOnline); + resolve(); }); }); } @@ -789,6 +754,8 @@ function GithubReleaseNotes(options) { GithubReleaseNotes.prototype.init = function() { var gren = this; + gren.tasks = []; + return hasNetwork() .then(function() { return generateOptions(gren.options); @@ -806,9 +773,6 @@ GithubReleaseNotes.prototype.init = function() { gren.repo = githubApi.getRepo(gren.options.username, gren.options.repo); gren.issues = githubApi.getIssues(gren.options.username, gren.options.repo); - }) - .catch(function(error) { - console.log(error); }); }; @@ -835,7 +799,7 @@ GithubReleaseNotes.prototype.release = function() { return getLastTags(gren, releases.length ? releases : false); }) .then(function(tags) { - loaded = utils.task('Getting the tag dates ranges'); + loaded = utils.task(gren, 'Getting the tag dates ranges'); return Promise.all(getTagDates(gren, tags)); }) @@ -849,14 +813,6 @@ GithubReleaseNotes.prototype.release = function() { }) .then(function(blocks) { return prepareRelease(gren, blocks[0]); - }) - .then(function(success) { - return success; - }) - .catch(function(error) { - console.error(error); - - return gren.options.force; }); }; @@ -879,11 +835,6 @@ GithubReleaseNotes.prototype.changelog = function() { }) .then(function(success) { return success; - }) - .catch(function(error) { - console.error(error); - - return gren.options.force; }); }; diff --git a/src/utils.js b/src/utils.js index 60c9653c..73644c5b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -23,22 +23,47 @@ function printTask(name) { * * @return {Function} The function to be fired when is loaded */ -function task(taskName) { +function task(gren, taskName) { var time = process.hrtime(); process.stdout.write(chalk.green(taskName) + ': .'); - var si = setInterval(function() { + gren.tasks[taskName] = setInterval(function() { process.stdout.write('.'); }, 100); return function(message) { var diff = process.hrtime(time); + var seconds = ((diff[0] * 1e9 + diff[1]) * 1e-9).toFixed(2); - process.stdout.write(message || '' + chalk.yellow(' (' + ((diff[0] * 1e9 + diff[1]) * 1e-9).toFixed(2) + ' secs)\n')); - clearInterval(si); + process.stdout.write(message || '' + chalk.yellow(' (' + seconds + ' secs)\n')); + clearInterval(gren.tasks[taskName]); + + gren.tasks[taskName] = seconds; }; } +/** + * Clears all the tasks that are still running + * + * @since 0.6.0 + * @public + * + * @param {GithubReleaseNotes} gren + */ +function clearTasks(gren) { + if (!gren.tasks.length) { + return; + } + + Object.keys(gren.tasks).forEach(function(taskName) { + clearInterval(gren.tasks[taskName]); + }); + + process.stdout.write(chalk.red('\nTask(s) stopped because of the following error:\n')); + + gren.tasks = []; +} + /** * Check if e value is between a min and a max * @@ -113,6 +138,7 @@ function formatDate(date) { module.exports = { printTask: printTask, task: task, + clearTasks: clearTasks, getBashOptions: getBashOptions, dashToCamelCase: dashToCamelCase, isInRange: isInRange,