#!/usr/bin/env ruby # encoding: utf-8 require File.dirname(__FILE__) + '/../lib/stagecoach.rb' CONFIG_FILE = `pwd`.chomp + '/.stagecoach' module Stagecoach staging = 'staging' master = 'master' # Command line options courtesy of the Trollop gem. opts = CommandLine.trollop # Initial setup with -s flag. if opts[:setup] Config.setup end # Initial setup without -s flag. unless File.exist?(CONFIG_FILE) Config.setup end # Load config file to a hash. config = Config.yaml_to_hash # Checks validity of argument variables. # Ignore these checks with -t flag. unless opts[:testing_given] Config.setup if config["redmine_site"] == "none" Config.setup if config["redmine_api"] == "none" # Checks that command-line args are present and correct. Trollop::die :planio, "issue number can only contain digits" if opts[:planio] && opts[:planio][/\D/] Trollop::die :github, "issue number can only contain digits" if opts[:github] && opts[:github][/\D/] Trollop::die :branch, "name must be longer than 1 character" if opts[:branch] && opts[:branch].length <= 1 # You can't give a planio and a github issue number (for the moment) if opts[:github] && opts[:planio] puts "You can't enter a github issue at the same time as a planio issue at the moment. Make up your mind!\nExiting..." exit end end # Set up redmine client config. RedmineApi::Client.instance_eval do self.site = config["redmine_site"] self.user = config["redmine_api_key"] end # Checks for uncommitted/unstashed changes and aborts if present. if Git.changes != '' puts "You have uncommitted changes:".red puts Git.changes puts "Please commit or stash these changes before running Stagecoach. -h for help." puts "Exiting..." exit end # Initial stage - set up branch and git issue. unless opts[:deploy] # If no issue argument has been given. if opts[:github].nil? && opts[:planio].nil? print "Are you working on a [P]lanio or a [G]ithub issue: " case STDIN.gets.chomp when 'P' print "Please enter your Planio issue number: " opts[:planio] = gets.chomp when 'G' print "Please enter your Github issue number: " opts[:github] = gets.chomp end end # Check that the planio issue is not already assigned. if opts[:planio] planio_issue_number = opts[:planio] planio_issue = Redmine.issue(planio_issue_number) if planio_issue.status.id != '1' puts "Warning!".red puts "This issue is in status '#{planio_issue.status.name}'" begin puts "It is assigned to #{planio_issue.assigned_to.name}" rescue puts "But it is not assigned to anybody yet." end print "Continue? [Y]es or [Q]uit: " case STDIN.gets.chomp when 'Y' when 'Q' exit end end # Set the planio issue status to 'In Bearbeitung' planio_issue.status_id = 2 planio_issue.save end # TODO: Check that the github issue is not already assigned. CommandLine.line_break puts "Stagecoach: initial stage" # Change to master, pull changes, and create a new branch. CommandLine.line_break puts "Switching to master branch" # # TODO if there is a file that has been git added but not git committed, it # will pop up at this point looking confusing (eg. "A test_file"). # Handle this better? # Git.checkout(master) puts "Pulling changes:" Git.pull if opts[:branch] new_branch = opts[:branch] else print "Please enter a new git branch name for your changes (branch will be created): " new_branch = STDIN.gets.chomp end # Check that the new branch isn't master, because that would be silly case new_branch when 'master', 'Master' puts "You can't use stagecoach to deploy your master branch.\nExiting..." exit end # Make sure new local branch does not already exist. if Git.branch_exist?(new_branch) puts "There is already a local branch called #{new_branch}." if Git.diff(master, new_branch) == "" print "#{new_branch} is up to date with master. [U]se or [Q]uit: " else puts "#{new_branch} is not up to date with master. Please use a different branch or update this one.".red puts "Exiting..." CommandLine.line_break puts "The following files in branch '#{new_branch}' differ from their master branch versions:" puts Git.diff(master, new_branch) CommandLine.line_break exit end case STDIN.gets.chomp when 'U' Git.change_to_branch(new_branch) when 'Q' exit end else Git.new_branch(new_branch) end # Ugly code, pretty output... CommandLine.line_break # Issue handling. if opts[:github] config[Git.current_branch] = {:github_issue => opts[:github]} #TODO check that github issue is not assigned to somebody already elsif opts[:planio] config[Git.current_branch] = {:planio_issue => planio_issue_number} end issue = config[Git.current_branch] # Set up the related issue for this branch. if planio_issue = issue[:planio_issue] begin puts "Searching for issue number #{planio_issue}..." redmine_issue = Redmine.issue(planio_issue) rescue ActiveResource::ResourceNotFound => e puts e.message exit end puts "Issue found: #{redmine_issue.subject}\n" # Create a Github issue referencing the planio issue. puts "Creating Git issue with subject: " + redmine_issue.subject body = "Planio issue: #{Redmine.issue_url(redmine_issue)} \n\n #{redmine_issue.description}" # Create a Git issue. github_issue = Git.new_issue(redmine_issue.subject, body) github_issue_id = github_issue[/\d+/] # Save it so we can reference it in commits using the magic of git hooks! config[Git.current_branch] = {:github_issue => github_issue_id, :planio_issue => planio_issue} print "Would you like to edit the issue on Github? [Y]es or anything else to continue: " if STDIN.gets.chomp == 'Y' Git.view_issue(github_issue_id) else end end # Github issues are easier. if issue[:github] #TODO what happens if no github issue is found? puts "Searching for github issue number #{issue[:number]}..." github_issue = Git.issue(issue[:number]) puts "Issue found: #{github_issue} \n" end # Saves the branch-specific details for later. Config.save(config) puts "Happy coding! Run stagecoach -d when you're ready to deploy." end # ------------------------------------------------------------------ # Deploy stage. if opts[:deploy] # Get the current git branch branch = Git.current_branch # There's no point in deploying without any commits unless Git.branch_has_commits?(branch) puts "You don't have any uncommitted changes on branch #{branch}. Please make some commits before running stagecoach!\nExiting..." exit end # You never know! Display git status in case there are any nasty surprises. unless Git.status =~ /nothing to commit/ CommandLine.line_break puts "You have a dirty git branch:\n".red puts Git.status CommandLine.line_break print "[D]eploy anyway".red print " or " print "[anything else] to cancel: ".green case STDIN.gets.chomp when "D" CommandLine.line_break puts "DEPLOYING:" CommandLine.line_break else puts "Exiting..." exit end end # Stop anybody deploying master to staging... case branch when 'master', 'Master' puts "You can't use stagecoach to deploy your master branch.\nExiting..." exit end # Finally, push, merge and deploy! Git.push(branch) Git.merge(staging, branch) Git.push(staging) Capistrano.deploy(staging) Git.change_to_branch(master) # Planio issue to feedback status if planio_issue_number = config[branch][:planio_issue] CommandLine.line_break puts "Attempting to change Planio ticket status to 'Feedback' for you:" issue = Redmine.issue(planio_issue_number) issue.status_id = 4 issue.save Redmine.view_issue(issue) end end end