diff --git a/.jscsrc b/.jscsrc index eb0a3c4..d242367 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,5 +1,4 @@ { - "additionalRules": ["rules/disallow-dot-notation-for-keywords.js"], "fileExtensions": [".js", ".jsx"], "disallowMixedSpacesAndTabs": true, "disallowNewlineBeforeBlockStatements": true, @@ -41,7 +40,7 @@ "safeContextKeyword": ["self"], "validateIndentation": 4, - "validateJSDoc": { + "jsDoc": { "checkParamNames": true, "checkRedundantParams": true, "requireParamTypes": true, diff --git a/README.md b/README.md index 7f25071..3ef648f 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,11 @@ A gulp plugin to pipe contents to github pull request comments. Features -------- -* Write collected info then comment on a github pull request. * Collect gulp-jshint results. * Collect gulp-jscs results. +* Write collected info then comment on a github pull request. +* Update github pull request status based on collected info. +* A failThisTask() reporter to fail a gulp task when jscs/jshint issues found * **TODO** Collect lcov result. Installation @@ -33,13 +35,21 @@ gulp.task('link_report_github', function () { return gulp.src('lib/*.js') .pipe(jshint()) .pipe(jscs()).on('error', function (E) { - console.log(E.message); // This handled jscs stream error + console.log(E.message); // This handled jscs stream error. }) - .pipe(github(options)); // comment issues in github PR! + .pipe(github(options)); // Comment issues in github PR! + .pipe(github.failThisTask()); // Fail this task when jscs/jshint issues found. }); // Or, direct output your comment with same options github.commentToPR('Yes! it works!!', options); + +// Or, direct set status to a commit +github.createStatusToCommit({ + description: 'No! 2 failures...', + context: 'my gulp task', + state: 'failure' +}, options); ``` Options @@ -81,3 +91,5 @@ Options ``` Check this sample gulpfile to see how to migrate this with travis CI. + +Check This PR to see live demo. Click on symbol before d9bc05e to see created status. diff --git a/gulpfile.js b/gulpfile.js index 1711300..a041e54 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -19,8 +19,8 @@ gulp.task('default', function () { git_prid: process.env.TRAVIS_PULL_REQUEST, git_sha: process.env.TRAVIS_COMMIT, - jshint_status: 'error', - jscs_status: 'failure', + jshint_status: 'error', // Set status to error when jshint errors + jscs_status: 'failure' // Set status to failure when jscs errors })) - .pipe(jshint.reporter('fail')); + .pipe(github.failThisTask()); }); diff --git a/index.js b/index.js index 88c5731..97d0676 100644 --- a/index.js +++ b/index.js @@ -27,16 +27,25 @@ getGIT = function (opt) { return GIT; }, -commentToPR = function (body, opt) { +closePR = function (opt, cb) { + getGIT(opt).issues.edit({ + user: opt.git_repo.split('/')[0], + repo: opt.git_repo.split('/')[1], + number: opt.git_prid, + state: 'closed' + }, cb); +}, + +commentToPR = function (body, opt, cb) { getGIT(opt).issues.createComment({ user: opt.git_repo.split('/')[0], repo: opt.git_repo.split('/')[1], number: opt.git_prid, body: body - }); + }, cb); }, -createStatusToCommit = function (state, opt) { +createStatusToCommit = function (state, opt, cb) { getGIT(opt).statuses.create({ user: opt.git_repo.split('/')[0], repo: opt.git_repo.split('/')[1], @@ -44,8 +53,108 @@ createStatusToCommit = function (state, opt) { state: state.state, description: state.description, context: state.context + }, cb); +}, + +isPullRequest = function (opt) { + return opt.git_token && opt.git_repo && opt.git_prid && (opt.git_prid !== 'false'); +}, + +isMerge = function (opt, callback) { + if (!isPullRequest(opt)) { + return; + } + + getGIT(opt).pullRequests.getCommits({ + user: opt.git_repo.split('/')[0], + repo: opt.git_repo.split('/')[1], + number: opt.git_prid, + per_page: 100 + }, function (E, D) { + var merged = []; + + if (E) { + console.warn(E); + return callback(E); + } + + D.forEach(function (commit) { + if (commit.parents.length > 1) { + merged.push('* Commit: @' + commit.sha + ' is a merge from ' + commit.parents.map(function (C) { + return '@' + C.sha; + }).join(' , ') + ' !!'); + } + }); + + callback(merged.length ? merged.join('\n') : false); }); -} +}, + +failMergedPR = function (opt, cb) { + var count = 0; + var err = []; + var done = function (E) { + count++; + if (E) { + err.push(E); + } + if ((count == 3) && cb) { + cb(err.length ? err : undefined); + } + }; + + isMerge(opt, function (M) { + if (!M) { + return; + } + + commentToPR('**Do not accept PR with merge, please use rebase always!**\n' + M, opt, done); + + createStatusToCommit({ + state: 'failure', + description: 'merge in PR', + context: 'gulp-github/is_merge' + }, opt, done); + + closePR(opt, done); + }); +}, + +failThisTask = function () { + var jshint_fails = 0, + jscs_fails = 0; + + return through.obj(function (file, enc, callback) { + if (file.jshint && !file.jshint.success && !file.jshint.ignored) { + jshint_fails += file.jshint.results.length; + } + + if (file.jscs && !file.jscs.success) { + jscs_fails += file.jscs.errors.length; + } + this.push(file); + callback(); + }, function (cb) { + var message = []; + + if (jshint_fails) { + message.push('found ' + jshint_fails + ' jshint issues'); + } + + if (jscs_fails) { + message.push('found ' + jscs_fails + ' jscs issues'); + } + + if (message.length) { + this.emit('error', new gutil.PluginError('gulp-github', { + message: 'Failed: ' + message.join(', ') + '.', + showStack: false + })); + } + + cb(); + }); +}; module.exports = function (options) { var jshint_output = ['**Please fix these jshint issues first:**'], @@ -71,12 +180,19 @@ module.exports = function (options) { callback(); }, function (cb) { var pr_url; + var count = 0; + var done = function () { + count--; + if (count == 0) { + cb(); + } + }; if ((jshint_output.length === 1) && (jscs_output.length === 1)) { return cb(); } - if (opt.git_token && opt.git_repo && opt.git_prid) { + if (isPullRequest(opt)) { pr_url = 'https://' + ((opt.git_option && opt.git_option.host) ? opt.git_option.host : 'github.com') + '/' + opt.git_repo + '/pull/' + opt.git_prid; if (jshint_output.length > 1) { commentToPR(jshint_output.join('\n'), opt); @@ -100,27 +216,37 @@ module.exports = function (options) { } if (opt.git_token && opt.git_repo && opt.git_sha) { + count++; if (jshint_output.length > 1) { if (opt.jshint_status) { + count++; createStatusToCommit({ state: opt.jshint_status, description: (jshint_output.length - 1) + ' jshint issues found', context: 'gulp-github/jshint' - }, opt); + }, opt, done); } + } + if (jscs_output.length > 1) { if (opt.jscs_status) { + count++; createStatusToCommit({ state: opt.jscs_status, description: (jscs_output.length - 1) + ' jscs issues found', context: 'gulp-github/jscs' - }, opt); + }, opt, done); } } } - cb(); + count++; + done(); }); }; module.exports.commentToPR = commentToPR; +module.exports.createStatusToCommit = createStatusToCommit; +module.exports.failThisTask = failThisTask; +module.exports.failMergedPR = failMergedPR; +module.exports.isMerge = isMerge; diff --git a/package.json b/package.json index 7c95847..13b6ed3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gulp-github", - "version": "0.1.0", + "version": "0.2.3", "description": "A gulp plugin to pipe contents to github pull request comments.", "author": "Zordius ", "contributors": [ @@ -26,14 +26,14 @@ }, "main": "index.js", "dependencies": { - "github": "0.2.3", - "gulp-util": "3.0.1", + "github": "0.2.4", + "gulp-util": "3.0.6", "through2": "*" }, "devDependencies": { - "gulp": "3.8.10", - "gulp-jshint": "1.9.0", - "gulp-jscs": "1.4.0" + "gulp": "3.9.0", + "gulp-jshint": "1.11.2", + "gulp-jscs": "2.0.0" }, "engines": { "node": ">=0.8"