diff --git a/.travis.yml b/.travis.yml index 72dbaa72b5..8a76cccab7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,6 @@ node_js: - 0.10 before_script: - npm install -g grunt-cli - - npm install -g jasmine-node \ No newline at end of file + - npm install -g jasmine-node +notifications: + irc: "chat.freenode.net#brackets" \ No newline at end of file diff --git a/package.json b/package.json index b74b56ea83..d135c68a1d 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ }, "scripts": { "postinstall": "grunt install", - "test": "grunt test" + "test": "grunt cla-check-pull" }, "licenses": [ { diff --git a/tasks/build.js b/tasks/build.js index ef00e3b33e..088f71db57 100644 --- a/tasks/build.js +++ b/tasks/build.js @@ -20,15 +20,19 @@ * DEALINGS IN THE SOFTWARE. * */ +/*jslint regexp:true*/ /*global module, require, process*/ module.exports = function (grunt) { "use strict"; - var build = {}, - child_process = require("child_process"), + var child_process = require("child_process"), + http = require("http"), + https = require("https"), + build = {}, path = require("path"), q = require("q"), + querystring = require("querystring"), qexec = q.denodeify(child_process.exec); function getGitInfo(cwd) { @@ -119,6 +123,131 @@ module.exports = function (grunt) { }); }); + // task: cla-check-pull + grunt.registerTask("cla-check-pull", "Check if a given GitHub user has signed the CLA", function () { + var done = this.async(), + body = "", + options = {}, + travis = process.env.TRAVIS === "true", + pull = travis ? process.env.TRAVIS_PULL_REQUEST : (grunt.option("pull") || false), + request; + + pull = parseInt(pull, 10); + + if (isNaN(pull)) { + grunt.log.writeln(JSON.stringify(process.env)); + + if (travis) { + // Kicked off a travis build without a pull request, skip CLA check + grunt.log.writeln("Travis build without pull request"); + done(); + } else { + // Grunt command-line option missing, fail CLA check + grunt.log.writeln("Missing pull request number. Use 'grunt cla-check-pull --pull='."); + done(false); + } + + return; + } + + options.host = "api.github.com"; + options.path = "/repos/adobe/brackets/issues/" + pull; + options.method = "GET"; + options.headers = { + "User-Agent" : "Node.js" + }; + + request = https.request(options, function (res) { + res.on("data", function (chunk) { + body += chunk; + }); + + res.on("end", function () { + var json = JSON.parse(body), + login = json.user && json.user.login; + + if (login) { + grunt.option("user", login); + grunt.task.run(["cla-check","test"]); + + done(); + } else { + grunt.log.writeln("Unexpected response from api.github.com"); + grunt.log.writeln("statusCode: " + res.statusCode); + grunt.log.writeln("headers: " + JSON.stringify(res.headers)); + grunt.log.writeln("data: " + body); + + done(false); + } + }); + + res.on("error", function (err) { + grunt.log.writeln(err); + done(false); + }); + }); + + request.end(); + }); + + // task: cla-check + grunt.registerTask("cla-check", "Check if a given GitHub user has signed the CLA", function () { + var done = this.async(), + user = grunt.option("user") || "", + body = "", + options = {}, + postdata = querystring.stringify({contributor: user}), + request; + + if (!user) { + grunt.log.writeln("Missing user name. Use 'grunt cla-check --user='."); + done(false); + return; + } + + // Check CLA exceptions first + var exceptions = grunt.file.readJSON("tasks/cla-exceptions.json"); + + if (exceptions[user]) { + grunt.log.writeln(user + " exempt from the standard contributor license agreement"); + done(); + return; + } + + // Query dev.brackets.io for CLA status + options.host = "dev.brackets.io"; + options.path = "/cla/brackets/check.cfm"; + options.method = "POST"; + options.headers = { + "Content-Type" : "application/x-www-form-urlencoded", + "Content-Length" : postdata.length + }; + + request = http.request(options, function (res) { + res.on("data", function (chunk) { + body += chunk; + }); + + res.on("end", function () { + if (body.match(/.*REJECTED.*/)) { + grunt.log.error(user + " has NOT submitted the contributor license agreement"); + done(false); + } else { + grunt.log.writeln(user + " has submitted the contributor license agreement"); + done(); + } + }); + + res.on("error", function (err) { + grunt.log.writeln(err); + done(false); + }); + }); + + request.write(postdata); + request.end(); + }); + build.getGitInfo = getGitInfo; return build; diff --git a/tasks/cla-exceptions.json b/tasks/cla-exceptions.json new file mode 100644 index 0000000000..4a79bc85c8 --- /dev/null +++ b/tasks/cla-exceptions.json @@ -0,0 +1,3 @@ +{ + "busykai": true +} \ No newline at end of file