diff --git a/deployment.coffee b/deployment.coffee index 1c3f8a1..27ec8fa 100644 --- a/deployment.coffee +++ b/deployment.coffee @@ -2,25 +2,192 @@ # Deployment script # # Commands: -# hubot deploy [from branch ] to [after [, , ...]] +# hubot deploy [with ] [from branch ] to [after [, , ...]] # # URLS: # # Notes: # +fs = require 'fs' + +deploymentDirectory = null module.exports = (robot) -> - robot.hear /deploy ([^\s]+)( from branch ([^\s]+))? to ([^\s]+)( after (.*))?$/i, (res) -> - project = res.match[1] - environnement = res.match[4] - branch = if res.match[3] then res.match[3] else null - commands = if res.match[6] then cleanCommands res.match[6].split(',') else [] + robot.hear /deploy set ([^\s]+) +(.+)$/i, (res) -> + if res.match[1] == "directory" + deploymentDirectory = res.match[2] + + robot.hear /deploy +([^\s]+)( +with +([^\s]+))?( +from +branch +([^\s]+))? +to +([^\s]+)( +after (.*))?$/i, (res) -> + + if ! process.env.hasOwnProperty('HUBO_DEPLOYMENT_PROJECTS_DIRECTORY') + if deploymentDirectory == null + res.reply "You must set the env var HUBO_DEPLOYMENT_PROJECTS_DIRECTORY with the directory of the projects." + res.reply "Temporaly, you can use the command: deploy set directory " + return + + project = res.match[1] + target = res.match[6] + program = if res.match[3] then res.match[3] else null + branch = if res.match[5] then res.match[5] else null + commands = if res.match[8] then cleanCommands res.match[8].split "," else [] + + if deploymentDirectory != null + directory = deploymentDirectory + else + directory = process.env.HUBO_DEPLOYMENT_PROJECTS_DIRECTORY + + directory += "/" + project + + try + fs.stat directory, (err, stats) -> + if err != null or !stats.isDirectory + return res.reply "Project not found [" + directory + "]" + + try + fs.statSync directory + '/.svn' + pv = new SvnProjectVersionning branch + catch e + + try + fs.statSync directory + '/.git' + pv = new GitProjectVersionning branch + catch e + + if pv + d = deploy directory, pv, commands, target, program + res.send d + else + res.reply "Not a SVN or GIT repository" + catch e + res.reply "Exception: " + e + +class ProjectVersionning + constructor: (@branch) -> + getUpdateCommands: () -> + +class SvnProjectVersionning extends ProjectVersionning + getUpdateCommands: () -> + ['svn up'] + +class GitProjectVersionning extends ProjectVersionning + getUpdateCommands: () -> + commands = [] + + if @branch == null + commands.push 'git pull origin $(git rev-parse --abbrev-ref HEAD)' + else + br = @branch.split "/" + + if br.length == 1 + commands.push 'git checkout ' + br[0] + commands.push 'git pull origin ' + br[0] + else if br.length == 2 + commands.push 'git checkout ' + br[1] + commands.push 'git pull ' + br.join(' ') + + commands + +logExec = (command, options) -> + exec = require "sync-exec" + exec command, options + + +deploy = (directory, projectVersionning, commands, target, program) -> + commands = projectVersionning.getUpdateCommands().concat(commands) + canDeploy = true + results = [] + + for command in commands + if !canDeploy + continue + + stmt = logExec command , {cwd: directory} + + results.push { + command: command, + status: stmt.status, + stdout: stmt.stdout, + stderr: stmt.stderr, + } + + if stmt.status != 0 + canDeploy = false + + if canDeploy + command = buildDeployCommand(directory, program, target) + stmt = logExec command, {cwd: directory} + + results.push { + command: command, + status: stmt.status, + stdout: stmt.stdout, + stderr: stmt.stderr, + } + + output = "" + + for stmt in results + output += generateOutput stmt + + output + +generateOutput = (stmt) -> + prefix = "deploy-" + Date.now() + status = + if stmt.status == 0 + "OK" + else + "Failed" + """ +

#{stmt.command}
#{status}

+
+ Outputs: STDOUT STDERR + + +
+ + """ + +buildDeployCommand = (directory, program, target) -> + if program == 'mage' + command = 'vendor/bin/mage deploy to:' + target + else + interpreter = null + + try + fs.statSync directory + '/bin/console' + interpreter = 'php bin/console' + catch e + + try + fs.statSync directory + '/app/console' + interpreter = 'php app/console' + catch e + + if interpreter != null + command = interpreter + ' project:deploy ' + target + ' --go' + + command cleanCommands = (commands) -> results = [] - commands = commands.map(Function.prototype.call, String.prototype.trim) + commands = commands.map Function.prototype.call, String.prototype.trim + + interpreters = { + "sf" : "php symfony", + "sf2" : "php app/console", + "sf3" : "php bin/console", + "composer": "composer" + } for command in commands - results.push(command) if command != '' - + if command != "" + if command.match /(sf[2-3]?|composer):.+/ + elements = command.split ":" + interpreter = elements[0] + elements = elements.splice 1 + args = elements.join(":") + results.push interpreters[interpreter] + " " + args + else + results.push command results