module Hoe::Travis

def define_travis_tasks

def define_travis_tasks
  desc "Runs your tests for travis"
  task :travis => %w[test check_manifest]
  namespace :travis do
    desc "Run by travis-ci after running the default checks"
    task :after => %w[
      travis:fake_config
    ]
    desc "Run by travis-ci before running the default checks"
    task :before => %w[
      install_plugins
      travis:install_deps
    ]
    desc "Lint your .travis.yml"
    task :check do
      abort unless travis_yml_check '.travis.yml'
    end
    desc "Disables the travis-ci hook"
    task :disable do
      travis_disable
    end
    desc "Brings .travis.yml up in your EDITOR then checks it on save"
    task :edit do
      Tempfile.open 'travis.yml' do |io|
        io.write File.read '.travis.yml'
        io.rewind
        ok = travis_yml_edit io.path
        travis_yml_write io.path if ok
      end
    end
    desc "Enables the travis-ci hook"
    task :enable do
      travis_enable
    end
    desc "Triggers the travis-ci hook"
    task :force do
      travis_force
    end
    task :fake_config do
      travis_fake_config
    end
    desc "Generates a new .travis.yml and allows you to customize it with your EDITOR"
    task :generate do
      Tempfile.open 'travis.yml' do |io|
        io.write travis_yml_generate
        io.rewind
        ok = travis_yml_edit io.path
        travis_yml_write io.path if ok
      end
    end
    task :install_deps do
      (extra_deps + extra_dev_deps).each do |dep|
        begin
          gem(*dep)
        rescue Gem::LoadError
          name, req, = dep
          install_gem name, req, false
        end
      end
    end
  end
end

def initialize_travis # :nodoc:

:nodoc:
def initialize_travis # :nodoc:
  @github_api = URI 'https://api.github.com'
end

def travis_after_script

def travis_after_script
  with_config { |config, _|
    config['travis']['after_script'] or
      Hoe::DEFAULT_CONFIG['travis']['after_script']
  }
end

def travis_before_script

def travis_before_script
  with_config { |config, _|
    config['travis']['before_script'] or
      Hoe::DEFAULT_CONFIG['travis']['before_script']
  }
end

def travis_disable

def travis_disable
  _, repo, = travis_github_check
  if hook = travis_have_hook?(repo) then
    travis_edit_hook repo, hook, false if hook['active']
  end
end

def travis_edit_hook repo, hook, enable = true

def travis_edit_hook repo, hook, enable = true
  patch = unless Net::HTTP.const_defined? :Patch then
            # Ruby 1.8
            Class.new Net::HTTPRequest do |c|
              c.const_set :METHOD, 'PATCH'
              c.const_set :REQUEST_HAS_BODY, true
              c.const_set :RESPONSE_HAS_BODY, true
            end
          else
            Net::HTTP::Patch
          end
  id = hook['id']
  body = {
    'name'   => hook['name'],
    'active' => enable,
    'config' => hook['config']
  }
  travis_github_request "/repos/#{repo}/hooks/#{id}", body, patch
end

def travis_enable

def travis_enable
  user, repo, token = travis_github_check
  if hook = travis_have_hook?(repo) then
    travis_edit_hook repo, hook unless hook['active']
  else
    travis_make_hook repo, user, token
  end
end

def travis_fake_config

def travis_fake_config
  fake_hoerc = File.expand_path '~/.hoerc'
  return if File.exist? fake_hoerc
  config = { 'exclude' => /\.(git|travis)/ }
  open fake_hoerc, 'w' do |io|
    YAML.dump config, io
  end
end

def travis_force

def travis_force
  user, repo, token = travis_github_check
  unless hook = travis_have_hook?(repo)
    hook = travis_make_hook repo, user, token
  end
  travis_github_request "/repos/#{repo}/hooks/#{hook['id']}/test", {}
end

def travis_github_check

def travis_github_check
  user = `git config github.user`.chomp
  abort <<-ABORT unless user
t your github user and token in ~/.gitconfig
e: ri Hoe::Travis and
http://help.github.com/set-your-user-name-email-and-github-token/
  ABORT
  `git config remote.origin.url` =~ /^git@github\.com:(.*).git$/
  repo = $1
  abort <<-ABORT unless repo
able to determine your github repository.
pected \"git@github.com:[repo].git\" as your remote origin
  ABORT
  token = with_config do |config, _|
    config['travis']['token']
  end
  abort 'Please set your travis token via `rake config_hoe` - ' \
        'See: ri Hoe::Travis' if token =~ /FIX/
  return user, repo, token
end

def travis_github_request(path, body = nil,

def travis_github_request(path, body = nil,
                          method = body ? Net::HTTP::Post : Net::HTTP::Get)
  begin
    require 'json'
  rescue LoadError => e
    raise unless e.message.end_with? 'json'
    abort 'Please gem install json like modern ruby versions have'
  end
  uri = @github_api + path
  http = Net::HTTP.new uri.host, uri.port
  http.use_ssl = uri.scheme.downcase == 'https'
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.cert_store = OpenSSL::X509::Store.new
  http.cert_store.set_default_paths
  req = method.new uri.request_uri
  if body then
    req.content_type = 'application/json'
    req.body = JSON.dump body
  end
  user = `git config github.user`.chomp
  pass = `git config github.password`.chomp
  req.basic_auth user, pass
  res = http.request req
  body = JSON.parse res.body if res.class.body_permitted?
  unless Net::HTTPSuccess === res then
    message = ": #{res['message']}" if body
    raise "github API error #{res.code}#{message}"
  end
  body
end

def travis_have_hook? repo

def travis_have_hook? repo
  body = travis_github_request "/repos/#{repo}/hooks"
  body.find { |hook| hook['name'] == 'travis' }
end

def travis_make_hook repo, user, token

def travis_make_hook repo, user, token
  body = {
    "name" => "travis",
    "active" => true,
    "config" => {
      "domain" => "",
      "token" => token,
      "user" => user,
    }
  }
  travis_github_request "/repos/#{repo}/hooks", body
end

def travis_notifications

def travis_notifications
  email = @email.compact
  email.delete ''
  default_notifications = { 'email' => email }
  notifications = with_config do |config, _|
    config['travis']['notifications'] or
      Hoe::DEFAULT_CONFIG['travis']['notifications']
  end || {}
  default_notifications.merge notifications
end

def travis_script

def travis_script
  with_config { |config, _|
    config['travis']['script'] or
      Hoe::DEFAULT_CONFIG['travis']['script']
  }
end

def travis_versions

def travis_versions
  if have_gem? 'ZenTest' and
     File.exist?(File.expand_path('~/.multiruby')) then
    `multiruby -v` =~ /^Passed: (.*)/
      $1.split(', ').map do |ruby_release|
      ruby_release.sub(/-.*/, '')
    end
  else
    with_config do |config, _|
      config['travis']['versions'] or
        Hoe::DEFAULT_CONFIG['travis']['versions']
    end
  end.sort
end

def travis_yml_check path

def travis_yml_check path
  require 'net/http'
  post_body = {
    'content' => File.read(path),
  }
  req = Net::HTTP::Post.new '/lint'
  req.set_form post_body, 'multipart/form-data'
  cert_store = OpenSSL::X509::Store.new
  cert_store.set_default_paths
  http = Net::HTTP.new 'api.travis-ci.org', 443
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.cert_store = cert_store
  res = http.request req
  unless Net::HTTPOK === res then
    warn "Unable to lint #{path}: #{res.body}"
    return false
  end
  require 'json'
  response = JSON.parse res.body
  lint     = response.fetch 'lint'
  warnings = lint.fetch 'warnings'
  return true if warnings.empty?
  warnings.each do |warning|
    keys    = warning.fetch 'key'
    message = warning.fetch 'message'
    if keys.empty? then
      warn message
    else
      warn "For #{keys.join ', '}: #{message}"
    end
  end
  return false
rescue Net::HTTPError => e
  warn "Unable to lint #{path}: #{e.message}"
  return false
end

def travis_yml_edit path

def travis_yml_edit path
  loop do
    editor = ENV['EDITOR'] || 'vi'
    system "#{editor} #{path}"
    break true if travis_yml_check path
    abort unless $stdout.tty?
    print "\nRetry edit? [Yn]\n> "
    $stdout.flush
    break false if $stdin.gets =~ /\An/i
  end
end

def travis_yml_generate

def travis_yml_generate
  travis_yml = {
    'after_script'  => travis_after_script,
    'before_script' => travis_before_script,
    'language'      => 'ruby',
    'notifications' => travis_notifications,
    'rvm'           => travis_versions,
    'script'        => travis_script,
  }
  travis_yml.each do |key, value|
    travis_yml.delete key unless value
  end
  YAML.dump travis_yml
end

def travis_yml_write source_file

def travis_yml_write source_file
  open source_file do |source_io|
    open '.travis.yml', 'w' do |dest_io|
      dest_io.write source_io.read
    end
  end
end