pagoda 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.bundle/config +2 -0
 - data/.gitignore +1 -0
 - data/Gemfile +4 -0
 - data/Gemfile.lock +39 -0
 - data/README +3 -0
 - data/Rakefile +11 -0
 - data/bin/pagoda +13 -0
 - data/lib/pagoda/client.rb +221 -0
 - data/lib/pagoda/command.rb +93 -0
 - data/lib/pagoda/commands/app.rb +243 -0
 - data/lib/pagoda/commands/auth.rb +149 -0
 - data/lib/pagoda/commands/base.rb +184 -0
 - data/lib/pagoda/commands/help.rb +100 -0
 - data/lib/pagoda/commands/tunnel.rb +49 -0
 - data/lib/pagoda/helpers.rb +127 -0
 - data/lib/pagoda/tunnel_proxy.rb +130 -0
 - data/lib/pagoda/version.rb +3 -0
 - data/lib/pagoda.rb +3 -0
 - data/pagoda.gemspec +29 -0
 - data/spec/base.rb +21 -0
 - data/spec/client_spec.rb +255 -0
 - data/spec/command_spec.rb +26 -0
 - data/spec/commands/auth_spec.rb +57 -0
 - metadata +167 -0
 
    
        data/.bundle/config
    ADDED
    
    
    
        data/.gitignore
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            pagoda-*.*.*.gem
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                pagoda (0.0.1)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  crack
         
     | 
| 
      
 6 
     | 
    
         
            +
                  iniparse
         
     | 
| 
      
 7 
     | 
    
         
            +
                  json_pure
         
     | 
| 
      
 8 
     | 
    
         
            +
                  rest-client
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 11 
     | 
    
         
            +
              remote: http://rubygems.org/
         
     | 
| 
      
 12 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 13 
     | 
    
         
            +
                addressable (2.2.5)
         
     | 
| 
      
 14 
     | 
    
         
            +
                crack (0.1.8)
         
     | 
| 
      
 15 
     | 
    
         
            +
                diff-lcs (1.1.2)
         
     | 
| 
      
 16 
     | 
    
         
            +
                iniparse (1.1.4)
         
     | 
| 
      
 17 
     | 
    
         
            +
                json_pure (1.5.1)
         
     | 
| 
      
 18 
     | 
    
         
            +
                mime-types (1.16)
         
     | 
| 
      
 19 
     | 
    
         
            +
                rest-client (1.6.1)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  mime-types (>= 1.16)
         
     | 
| 
      
 21 
     | 
    
         
            +
                rspec (2.5.0)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  rspec-core (~> 2.5.0)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  rspec-expectations (~> 2.5.0)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  rspec-mocks (~> 2.5.0)
         
     | 
| 
      
 25 
     | 
    
         
            +
                rspec-core (2.5.1)
         
     | 
| 
      
 26 
     | 
    
         
            +
                rspec-expectations (2.5.0)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  diff-lcs (~> 1.1.2)
         
     | 
| 
      
 28 
     | 
    
         
            +
                rspec-mocks (2.5.0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                webmock (1.6.2)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  addressable (>= 2.2.2)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  crack (>= 0.1.7)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 34 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 37 
     | 
    
         
            +
              pagoda!
         
     | 
| 
      
 38 
     | 
    
         
            +
              rspec
         
     | 
| 
      
 39 
     | 
    
         
            +
              webmock
         
     | 
    
        data/README
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/pagoda
    ADDED
    
    | 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
         
     | 
| 
      
 4 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'pagoda/client'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'pagoda/command'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            args = ARGV.dup
         
     | 
| 
      
 10 
     | 
    
         
            +
            ARGV.clear
         
     | 
| 
      
 11 
     | 
    
         
            +
            command = args.shift.strip rescue 'help'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Pagoda::Command.run(command, args)
         
     | 
| 
         @@ -0,0 +1,221 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'pagoda/version'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rexml/document'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rest_client'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'json/pure' unless {}.respond_to?(:to_json)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class Pagoda::Client
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              attr_reader :user, :password
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 12 
     | 
    
         
            +
                def version
         
     | 
| 
      
 13 
     | 
    
         
            +
                  Pagoda::VERSION
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                def gem_version_string
         
     | 
| 
      
 17 
     | 
    
         
            +
                  "pagoda-gem/#{version}"
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              def initialize(user, password)
         
     | 
| 
      
 22 
     | 
    
         
            +
                @user       = user
         
     | 
| 
      
 23 
     | 
    
         
            +
                @password   = password
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
              
         
     | 
| 
      
 26 
     | 
    
         
            +
              def app_list
         
     | 
| 
      
 27 
     | 
    
         
            +
                doc = xml(get("/apps.xml").to_s)
         
     | 
| 
      
 28 
     | 
    
         
            +
                doc.elements['apps'].elements.to_a('//app/').inject([]) do |list, app| 
         
     | 
| 
      
 29 
     | 
    
         
            +
                  list <<  {
         
     | 
| 
      
 30 
     | 
    
         
            +
                      :name => app.elements['name'].text,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      :instances => app.elements['instances'].text,
         
     | 
| 
      
 32 
     | 
    
         
            +
                      :git_url => app.elements['git-url'].text
         
     | 
| 
      
 33 
     | 
    
         
            +
                    }
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
              def database_exists?(app, mysql_instance)
         
     | 
| 
      
 38 
     | 
    
         
            +
                begin
         
     | 
| 
      
 39 
     | 
    
         
            +
                  response = get("/apps/#{app}/databases/#{mysql_instance}.xml")
         
     | 
| 
      
 40 
     | 
    
         
            +
                  true
         
     | 
| 
      
 41 
     | 
    
         
            +
                rescue RestClient::ResourceNotFound => e
         
     | 
| 
      
 42 
     | 
    
         
            +
                  false
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
              def app_create(name, git_url)
         
     | 
| 
      
 48 
     | 
    
         
            +
                doc = xml(post("/apps.xml", {:app => {:name => name, :git_url => git_url}}).to_s)
         
     | 
| 
      
 49 
     | 
    
         
            +
                doc.elements.to_a('//app/*').inject({}) do |hash, element|
         
     | 
| 
      
 50 
     | 
    
         
            +
                  case element.name
         
     | 
| 
      
 51 
     | 
    
         
            +
                    when "owner"
         
     | 
| 
      
 52 
     | 
    
         
            +
                      hash[:owner] = {:username => element.elements['username'].text, :email => element.elements['email'].text}
         
     | 
| 
      
 53 
     | 
    
         
            +
                    when "collaborators"
         
     | 
| 
      
 54 
     | 
    
         
            +
                      hash[:collaborators] = element.elements.to_a('//collaborator/').inject([]) do |list, collaborator|
         
     | 
| 
      
 55 
     | 
    
         
            +
                        list << {:username => collaborator.elements['username'].text, :email => collaborator.elements['email'].text}
         
     | 
| 
      
 56 
     | 
    
         
            +
                      end
         
     | 
| 
      
 57 
     | 
    
         
            +
                    when "transactions"
         
     | 
| 
      
 58 
     | 
    
         
            +
                      hash[:transactions] = element.elements.to_a('//transaction/').inject([]) do |list, transaction|
         
     | 
| 
      
 59 
     | 
    
         
            +
                        list << {
         
     | 
| 
      
 60 
     | 
    
         
            +
                            :id          => transaction.elements["id"].text,
         
     | 
| 
      
 61 
     | 
    
         
            +
                            :name        => transaction.elements["name"].text,
         
     | 
| 
      
 62 
     | 
    
         
            +
                            :description => transaction.elements["description"].text,
         
     | 
| 
      
 63 
     | 
    
         
            +
                            :state       => transaction.elements["state"].text,
         
     | 
| 
      
 64 
     | 
    
         
            +
                            :status      => transaction.elements["status"].text
         
     | 
| 
      
 65 
     | 
    
         
            +
                          }
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    else
         
     | 
| 
      
 68 
     | 
    
         
            +
                      hash[element.name.gsub(/-/, '_').to_sym] = element.text
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  hash
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
              
         
     | 
| 
      
 74 
     | 
    
         
            +
              def app_info(app)
         
     | 
| 
      
 75 
     | 
    
         
            +
                doc = xml(get("/apps/#{app}.xml").to_s)
         
     | 
| 
      
 76 
     | 
    
         
            +
                doc.elements.to_a('//app/*').inject({}) do |hash, element|
         
     | 
| 
      
 77 
     | 
    
         
            +
                  case element.name
         
     | 
| 
      
 78 
     | 
    
         
            +
                    when "owner"
         
     | 
| 
      
 79 
     | 
    
         
            +
                      hash[:owner] = {:username => element.elements['username'].text, :email => element.elements['email'].text}
         
     | 
| 
      
 80 
     | 
    
         
            +
                    when "collaborators"
         
     | 
| 
      
 81 
     | 
    
         
            +
                      hash[:collaborators] = element.elements.to_a('//collaborator/').inject([]) do |list, collaborator|
         
     | 
| 
      
 82 
     | 
    
         
            +
                        list << {:username => collaborator.elements['username'].text, :email => collaborator.elements['email'].text}
         
     | 
| 
      
 83 
     | 
    
         
            +
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
                    when "transactions"
         
     | 
| 
      
 85 
     | 
    
         
            +
                      hash[:transactions] = element.elements.to_a('//transaction/').inject([]) do |list, transaction|
         
     | 
| 
      
 86 
     | 
    
         
            +
                        list << {
         
     | 
| 
      
 87 
     | 
    
         
            +
                            :id          => transaction.elements["id"].text,
         
     | 
| 
      
 88 
     | 
    
         
            +
                            :name        => transaction.elements["name"].text,
         
     | 
| 
      
 89 
     | 
    
         
            +
                            :description => transaction.elements["description"].text,
         
     | 
| 
      
 90 
     | 
    
         
            +
                            :state       => transaction.elements["state"].text,
         
     | 
| 
      
 91 
     | 
    
         
            +
                            :status      => transaction.elements["status"].text
         
     | 
| 
      
 92 
     | 
    
         
            +
                          }
         
     | 
| 
      
 93 
     | 
    
         
            +
                      end
         
     | 
| 
      
 94 
     | 
    
         
            +
                    else
         
     | 
| 
      
 95 
     | 
    
         
            +
                      hash[element.name.gsub(/-/, '_').to_sym] = element.text
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  hash
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
              end
         
     | 
| 
      
 100 
     | 
    
         
            +
              
         
     | 
| 
      
 101 
     | 
    
         
            +
              def app_update(app, updates)
         
     | 
| 
      
 102 
     | 
    
         
            +
                put("/apps/#{app}.xml", {:update => updates}).to_s
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
              
         
     | 
| 
      
 105 
     | 
    
         
            +
              def app_destroy(app)
         
     | 
| 
      
 106 
     | 
    
         
            +
                delete("/apps/#{app}.xml").to_s
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
              
         
     | 
| 
      
 109 
     | 
    
         
            +
              def transaction_list(app)
         
     | 
| 
      
 110 
     | 
    
         
            +
                doc = xml(get("/apps/#{app}/transactions.xml").to_s)
         
     | 
| 
      
 111 
     | 
    
         
            +
                doc.elements['transactions'].elements.to_a('//transaction/').inject([]) do |list, transaction| 
         
     | 
| 
      
 112 
     | 
    
         
            +
                  list <<  {
         
     | 
| 
      
 113 
     | 
    
         
            +
                      :id          => transaction.elements['id'].text,
         
     | 
| 
      
 114 
     | 
    
         
            +
                      :name        => transaction.elements['name'].text,
         
     | 
| 
      
 115 
     | 
    
         
            +
                      :description => transaction.elements['description'].text,
         
     | 
| 
      
 116 
     | 
    
         
            +
                      :state       => transaction.elements['state'].text,
         
     | 
| 
      
 117 
     | 
    
         
            +
                      :status      => transaction.elements['status'].text
         
     | 
| 
      
 118 
     | 
    
         
            +
                    }
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
              
         
     | 
| 
      
 122 
     | 
    
         
            +
              def transaction_status(app, transaction)
         
     | 
| 
      
 123 
     | 
    
         
            +
                doc = xml(get("/apps/#{app}/transactions/#{transaction}.xml").to_s)
         
     | 
| 
      
 124 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 125 
     | 
    
         
            +
              end
         
     | 
| 
      
 126 
     | 
    
         
            +
              
         
     | 
| 
      
 127 
     | 
    
         
            +
              def rewind(app, places=1)
         
     | 
| 
      
 128 
     | 
    
         
            +
                doc = xml(put("/apps/#{app}/rewind.xml", {:places => places}).to_s)
         
     | 
| 
      
 129 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 130 
     | 
    
         
            +
              end
         
     | 
| 
      
 131 
     | 
    
         
            +
              
         
     | 
| 
      
 132 
     | 
    
         
            +
              def fast_forward(app, places=1)
         
     | 
| 
      
 133 
     | 
    
         
            +
                doc = xml(put("/apps/#{app}/fast-forward.xml", {:places => places}).to_s)
         
     | 
| 
      
 134 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 135 
     | 
    
         
            +
              end
         
     | 
| 
      
 136 
     | 
    
         
            +
              
         
     | 
| 
      
 137 
     | 
    
         
            +
              def rollback(app)
         
     | 
| 
      
 138 
     | 
    
         
            +
                get("/apps/#{app}/rollback.xml").to_s
         
     | 
| 
      
 139 
     | 
    
         
            +
              end
         
     | 
| 
      
 140 
     | 
    
         
            +
              
         
     | 
| 
      
 141 
     | 
    
         
            +
              def deploy_latest(app)
         
     | 
| 
      
 142 
     | 
    
         
            +
                doc = xml(post("/apps/#{app}/deploy.xml").to_s)
         
     | 
| 
      
 143 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 144 
     | 
    
         
            +
              end
         
     | 
| 
      
 145 
     | 
    
         
            +
              
         
     | 
| 
      
 146 
     | 
    
         
            +
              def deploy(app, branch, commit)
         
     | 
| 
      
 147 
     | 
    
         
            +
                doc = xml(post("/apps/#{app}/deploy.xml", {:deploy => {:branch => branch, :commit => commit}}).to_s)
         
     | 
| 
      
 148 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
              
         
     | 
| 
      
 151 
     | 
    
         
            +
              # def deploy(app)
         
     | 
| 
      
 152 
     | 
    
         
            +
              #   doc = xml(put("/apps/#{app}/deploy.xml").to_s)
         
     | 
| 
      
 153 
     | 
    
         
            +
              #   doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 154 
     | 
    
         
            +
              # end
         
     | 
| 
      
 155 
     | 
    
         
            +
              
         
     | 
| 
      
 156 
     | 
    
         
            +
              def scale_up(app, qty=1)
         
     | 
| 
      
 157 
     | 
    
         
            +
                doc = xml(put("/apps/#{app}/scale-up.xml").to_s)
         
     | 
| 
      
 158 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 159 
     | 
    
         
            +
              end
         
     | 
| 
      
 160 
     | 
    
         
            +
              
         
     | 
| 
      
 161 
     | 
    
         
            +
              def scale_down(app, qty=1)
         
     | 
| 
      
 162 
     | 
    
         
            +
                doc = xml(put("/apps/#{app}/scale-down.xml").to_s)
         
     | 
| 
      
 163 
     | 
    
         
            +
                doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
              
         
     | 
| 
      
 166 
     | 
    
         
            +
              def app_databases(app)
         
     | 
| 
      
 167 
     | 
    
         
            +
                doc = xml(get("/apps/#{app}/databases.xml").to_s)
         
     | 
| 
      
 168 
     | 
    
         
            +
                doc.elements['databases'].elements.to_a('//database/').inject([]) {|list, instance| list <<  {:name => instance.elements['name'].text} }
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
              
         
     | 
| 
      
 171 
     | 
    
         
            +
              def on_warning(&blk)
         
     | 
| 
      
 172 
     | 
    
         
            +
                @warning_callback = blk
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
              
         
     | 
| 
      
 175 
     | 
    
         
            +
              protected
         
     | 
| 
      
 176 
     | 
    
         
            +
              
         
     | 
| 
      
 177 
     | 
    
         
            +
              def resource(uri)
         
     | 
| 
      
 178 
     | 
    
         
            +
                RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
         
     | 
| 
      
 179 
     | 
    
         
            +
                if uri =~ /^https?/
         
     | 
| 
      
 180 
     | 
    
         
            +
                  RestClient::Resource.new(uri, @user, @password)
         
     | 
| 
      
 181 
     | 
    
         
            +
                else
         
     | 
| 
      
 182 
     | 
    
         
            +
                  # RestClient::Resource.new("http://127.0.0.1:3000#{uri}", @user, @password)
         
     | 
| 
      
 183 
     | 
    
         
            +
                  RestClient::Resource.new("https://dashboard.pagodabox.com#{uri}", @user, @password)
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
              def get(uri, extra_headers={})
         
     | 
| 
      
 188 
     | 
    
         
            +
                process(:get, uri, extra_headers)
         
     | 
| 
      
 189 
     | 
    
         
            +
              end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
              def post(uri, payload="", extra_headers={})    
         
     | 
| 
      
 192 
     | 
    
         
            +
                process(:post, uri, extra_headers, payload)
         
     | 
| 
      
 193 
     | 
    
         
            +
              end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
              def put(uri, payload="", extra_headers={})    
         
     | 
| 
      
 196 
     | 
    
         
            +
                process(:put, uri, extra_headers, payload)
         
     | 
| 
      
 197 
     | 
    
         
            +
              end
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
              def delete(uri, extra_headers={})    
         
     | 
| 
      
 200 
     | 
    
         
            +
                process(:delete, uri, extra_headers)
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              def process(method, uri, extra_headers={}, payload=nil)
         
     | 
| 
      
 204 
     | 
    
         
            +
                headers  = pagoda_headers.merge(extra_headers)
         
     | 
| 
      
 205 
     | 
    
         
            +
                args     = [method, payload, headers].compact
         
     | 
| 
      
 206 
     | 
    
         
            +
                response = resource(uri).send(*args)
         
     | 
| 
      
 207 
     | 
    
         
            +
              end
         
     | 
| 
      
 208 
     | 
    
         
            +
              
         
     | 
| 
      
 209 
     | 
    
         
            +
              def pagoda_headers
         
     | 
| 
      
 210 
     | 
    
         
            +
                {
         
     | 
| 
      
 211 
     | 
    
         
            +
                  'User-Agent'           => self.class.gem_version_string,
         
     | 
| 
      
 212 
     | 
    
         
            +
                  'X-Ruby-Version'       => RUBY_VERSION,
         
     | 
| 
      
 213 
     | 
    
         
            +
                  'X-Ruby-Platform'      => RUBY_PLATFORM,
         
     | 
| 
      
 214 
     | 
    
         
            +
                }
         
     | 
| 
      
 215 
     | 
    
         
            +
              end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
              def xml(raw)   # :nodoc:
         
     | 
| 
      
 218 
     | 
    
         
            +
                REXML::Document.new(raw)
         
     | 
| 
      
 219 
     | 
    
         
            +
              end
         
     | 
| 
      
 220 
     | 
    
         
            +
              
         
     | 
| 
      
 221 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'pagoda/helpers'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'pagoda/tunnel_proxy'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'pagoda/commands/base'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Pagoda
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Command
         
     | 
| 
      
 9 
     | 
    
         
            +
                class InvalidCommand < RuntimeError; end
         
     | 
| 
      
 10 
     | 
    
         
            +
                class CommandFailed  < RuntimeError; end
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                extend Pagoda::Helpers
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 15 
     | 
    
         
            +
                  
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def run(command, args, retries=0)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 18 
     | 
    
         
            +
                      run_internal 'auth:reauthorize', args.dup if retries > 0
         
     | 
| 
      
 19 
     | 
    
         
            +
                      run_internal(command, args.dup)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    rescue InvalidCommand
         
     | 
| 
      
 21 
     | 
    
         
            +
                      error "Unknown command: #{command}. Run 'pagoda help' for usage information."
         
     | 
| 
      
 22 
     | 
    
         
            +
                    rescue RestClient::Unauthorized
         
     | 
| 
      
 23 
     | 
    
         
            +
                      if retries < 3
         
     | 
| 
      
 24 
     | 
    
         
            +
                        STDERR.puts "Authentication failure"
         
     | 
| 
      
 25 
     | 
    
         
            +
                        run(command, args, retries+1)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      else
         
     | 
| 
      
 27 
     | 
    
         
            +
                        error "Authentication failure"
         
     | 
| 
      
 28 
     | 
    
         
            +
                      end
         
     | 
| 
      
 29 
     | 
    
         
            +
                    rescue RestClient::ResourceNotFound => e
         
     | 
| 
      
 30 
     | 
    
         
            +
                      error extract_not_found(e.http_body)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    rescue RestClient::RequestFailed => e
         
     | 
| 
      
 32 
     | 
    
         
            +
                      error extract_error(e.http_body) unless e.http_code == 402 || e.http_code == 102
         
     | 
| 
      
 33 
     | 
    
         
            +
                    rescue RestClient::RequestTimeout
         
     | 
| 
      
 34 
     | 
    
         
            +
                      error "API request timed out. Please try again, or contact support@pagodagrid.com if this issue persists."
         
     | 
| 
      
 35 
     | 
    
         
            +
                    rescue CommandFailed => e
         
     | 
| 
      
 36 
     | 
    
         
            +
                      error e.message
         
     | 
| 
      
 37 
     | 
    
         
            +
                    rescue Interrupt => e
         
     | 
| 
      
 38 
     | 
    
         
            +
                      error "\n[canceled]"
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  def run_internal(command, args)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    klass, method = parse(command)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    runner = klass.new(args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    raise InvalidCommand unless runner.respond_to?(method)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    runner.send(method)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def parse(command)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    parts = command.split(':')
         
     | 
| 
      
 51 
     | 
    
         
            +
                    case parts.size
         
     | 
| 
      
 52 
     | 
    
         
            +
                      when 1
         
     | 
| 
      
 53 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 54 
     | 
    
         
            +
                          return eval("Pagoda::Command::#{command.capitalize}"), :index
         
     | 
| 
      
 55 
     | 
    
         
            +
                        rescue NameError, NoMethodError
         
     | 
| 
      
 56 
     | 
    
         
            +
                          return Pagoda::Command::App, command.to_sym
         
     | 
| 
      
 57 
     | 
    
         
            +
                        end
         
     | 
| 
      
 58 
     | 
    
         
            +
                      else
         
     | 
| 
      
 59 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 60 
     | 
    
         
            +
                          const = Pagoda::Command
         
     | 
| 
      
 61 
     | 
    
         
            +
                          command = parts.pop
         
     | 
| 
      
 62 
     | 
    
         
            +
                          parts.each { |part| const = const.const_get(part.capitalize) }
         
     | 
| 
      
 63 
     | 
    
         
            +
                          return const, command.to_sym
         
     | 
| 
      
 64 
     | 
    
         
            +
                        rescue NameError
         
     | 
| 
      
 65 
     | 
    
         
            +
                          raise InvalidCommand
         
     | 
| 
      
 66 
     | 
    
         
            +
                        end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  def extract_not_found(body)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    body =~ /^[\w\s]+ not found$/ ? body : "Resource not found"
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def extract_error(body)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    msg = parse_error_xml(body) || parse_error_json(body) || 'Internal server error'
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  def parse_error_xml(body)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    xml_errors = REXML::Document.new(body).elements.to_a("//errors/error")
         
     | 
| 
      
 80 
     | 
    
         
            +
                    msg = xml_errors.map { |a| a.text }.join(" / ")
         
     | 
| 
      
 81 
     | 
    
         
            +
                    return msg unless msg.empty?
         
     | 
| 
      
 82 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def parse_error_json(body)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    json = JSON.parse(body.to_s)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    json['error']
         
     | 
| 
      
 88 
     | 
    
         
            +
                  rescue JSON::ParserError
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
                
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,243 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pagoda::Command
         
     | 
| 
      
 2 
     | 
    
         
            +
              class App < Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                
         
     | 
| 
      
 4 
     | 
    
         
            +
                def list
         
     | 
| 
      
 5 
     | 
    
         
            +
                  apps = client.app_list
         
     | 
| 
      
 6 
     | 
    
         
            +
                  if !apps.empty?
         
     | 
| 
      
 7 
     | 
    
         
            +
                    display
         
     | 
| 
      
 8 
     | 
    
         
            +
                    display "APPS"
         
     | 
| 
      
 9 
     | 
    
         
            +
                    display "//////////////////////////////////"
         
     | 
| 
      
 10 
     | 
    
         
            +
                    display
         
     | 
| 
      
 11 
     | 
    
         
            +
                    apps.each do |app|
         
     | 
| 
      
 12 
     | 
    
         
            +
                      display "- #{app[:name]}"
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  else
         
     | 
| 
      
 15 
     | 
    
         
            +
                    error ["looks like you haven't launched any apps", "type 'pagoda launch' to launch this project"]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  display
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                def create
         
     | 
| 
      
 21 
     | 
    
         
            +
                  if app_name = app(true)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    error ["This project is already launched and paired to #{app_name}.", "To unpair run 'pagoda unpair'"]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  
         
     | 
| 
      
 25 
     | 
    
         
            +
                  unless locate_app_root
         
     | 
| 
      
 26 
     | 
    
         
            +
                    error ["Unable to find git config in this directory or in any parent directory"]
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  
         
     | 
| 
      
 29 
     | 
    
         
            +
                  unless clone_url = extract_git_clone_url
         
     | 
| 
      
 30 
     | 
    
         
            +
                    errors = []
         
     | 
| 
      
 31 
     | 
    
         
            +
                    errors << "It appears you are using git (fantastic)."
         
     | 
| 
      
 32 
     | 
    
         
            +
                    errors << "However we only support git repos hosted with github."
         
     | 
| 
      
 33 
     | 
    
         
            +
                    errors << "Please ensure your repo is hosted with github."
         
     | 
| 
      
 34 
     | 
    
         
            +
                    error errors
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  
         
     | 
| 
      
 37 
     | 
    
         
            +
                  unless name = args.dup.shift
         
     | 
| 
      
 38 
     | 
    
         
            +
                    error "Please Specify an app name ie. 'pagoda launch awesomeapp'"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  
         
     | 
| 
      
 41 
     | 
    
         
            +
                  display
         
     | 
| 
      
 42 
     | 
    
         
            +
                  display "+> Registering #{name}"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  app = client.app_create(name, clone_url)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  display "+> Launching...", false
         
     | 
| 
      
 45 
     | 
    
         
            +
                  loop_transaction(name)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  add_app(name, clone_url)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  display "+> #{name} launched"
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  unless option_value(nil, "--latest")
         
     | 
| 
      
 50 
     | 
    
         
            +
                    Pagoda::Command.run_internal("app:deploy", args)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  
         
     | 
| 
      
 53 
     | 
    
         
            +
                  display "-----------------------------------------------"
         
     | 
| 
      
 54 
     | 
    
         
            +
                  display
         
     | 
| 
      
 55 
     | 
    
         
            +
                  display "LIVE URL    : http://#{name}.pagodabox.com"
         
     | 
| 
      
 56 
     | 
    
         
            +
                  display "ADMIN PANEL : http://dashboard.pagodabox.com"
         
     | 
| 
      
 57 
     | 
    
         
            +
                  display
         
     | 
| 
      
 58 
     | 
    
         
            +
                  display "-----------------------------------------------"
         
     | 
| 
      
 59 
     | 
    
         
            +
                  display
         
     | 
| 
      
 60 
     | 
    
         
            +
                  
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
                alias :launch :create
         
     | 
| 
      
 63 
     | 
    
         
            +
                alias :register :create
         
     | 
| 
      
 64 
     | 
    
         
            +
                
         
     | 
| 
      
 65 
     | 
    
         
            +
                def destroy
         
     | 
| 
      
 66 
     | 
    
         
            +
                  display
         
     | 
| 
      
 67 
     | 
    
         
            +
                  if confirm ["Are you totally completely sure you want to delete #{app} forever and ever?", "THIS CANNOT BE UNDONE! (y/n)"]
         
     | 
| 
      
 68 
     | 
    
         
            +
                    display "+> Destroying #{app}"
         
     | 
| 
      
 69 
     | 
    
         
            +
                    client.app_destroy(app)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    display "+> #{app} has been successfully destroyed. RIP #{app}."
         
     | 
| 
      
 71 
     | 
    
         
            +
                    remove_app(app)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  display
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
                alias :delete :destroy
         
     | 
| 
      
 76 
     | 
    
         
            +
                
         
     | 
| 
      
 77 
     | 
    
         
            +
                def info
         
     | 
| 
      
 78 
     | 
    
         
            +
                  display
         
     | 
| 
      
 79 
     | 
    
         
            +
                  info = client.app_info(app)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  display "INFO - #{info[:name]}"
         
     | 
| 
      
 81 
     | 
    
         
            +
                  display "//////////////////////////////////"
         
     | 
| 
      
 82 
     | 
    
         
            +
                  display "name       :  #{info[:name]}"
         
     | 
| 
      
 83 
     | 
    
         
            +
                  display "clone_url  :  #{info[:git_url]}"
         
     | 
| 
      
 84 
     | 
    
         
            +
                  display  
         
     | 
| 
      
 85 
     | 
    
         
            +
                  display "owner"
         
     | 
| 
      
 86 
     | 
    
         
            +
                  display "username :  #{info[:owner][:username]}", true, 2
         
     | 
| 
      
 87 
     | 
    
         
            +
                  display "email    :  #{info[:owner][:email]}", true, 2
         
     | 
| 
      
 88 
     | 
    
         
            +
                  display  
         
     | 
| 
      
 89 
     | 
    
         
            +
                  display "collaborators"
         
     | 
| 
      
 90 
     | 
    
         
            +
                  if info[:collaborators].any?
         
     | 
| 
      
 91 
     | 
    
         
            +
                    info[:collaborators].each_with_index do |collaborator, index|
         
     | 
| 
      
 92 
     | 
    
         
            +
                      display "username :  #{collaborator[:username]}", true, 2
         
     | 
| 
      
 93 
     | 
    
         
            +
                      display "email    :  #{collaborator[:email]}", true, 2
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  else
         
     | 
| 
      
 96 
     | 
    
         
            +
                    display "(none)", true, 2
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  display
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
                
         
     | 
| 
      
 101 
     | 
    
         
            +
                def pair
         
     | 
| 
      
 102 
     | 
    
         
            +
                  
         
     | 
| 
      
 103 
     | 
    
         
            +
                  if app_name = app(true)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    error ["This project is paired to #{app_name}.", "To unpair run 'pagoda unpair'"]
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                  
         
     | 
| 
      
 107 
     | 
    
         
            +
                  unless locate_app_root
         
     | 
| 
      
 108 
     | 
    
         
            +
                    error ["Unable to find git config in this directory or in any parent directory"]
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
                  
         
     | 
| 
      
 111 
     | 
    
         
            +
                  unless my_repo = extract_git_clone_url
         
     | 
| 
      
 112 
     | 
    
         
            +
                    errors = []
         
     | 
| 
      
 113 
     | 
    
         
            +
                    errors << "It appears you are using git (fantastic)."
         
     | 
| 
      
 114 
     | 
    
         
            +
                    errors << "However we only support git repos hosted with github."
         
     | 
| 
      
 115 
     | 
    
         
            +
                    errors << "Please ensure your repo is hosted with github."
         
     | 
| 
      
 116 
     | 
    
         
            +
                    error errors
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
                  
         
     | 
| 
      
 119 
     | 
    
         
            +
                  display
         
     | 
| 
      
 120 
     | 
    
         
            +
                  display "+> Locating deployed app with matching git repo"
         
     | 
| 
      
 121 
     | 
    
         
            +
                  
         
     | 
| 
      
 122 
     | 
    
         
            +
                  apps = client.app_list
         
     | 
| 
      
 123 
     | 
    
         
            +
                  
         
     | 
| 
      
 124 
     | 
    
         
            +
                  matching_apps = []
         
     | 
| 
      
 125 
     | 
    
         
            +
                  apps.each do |a|
         
     | 
| 
      
 126 
     | 
    
         
            +
                    if a[:git_url] == my_repo
         
     | 
| 
      
 127 
     | 
    
         
            +
                      matching_apps.push a
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  
         
     | 
| 
      
 131 
     | 
    
         
            +
                  if matching_apps.count > 1
         
     | 
| 
      
 132 
     | 
    
         
            +
                    if name = app(true) || args.dup.shift
         
     | 
| 
      
 133 
     | 
    
         
            +
                      assign_app = nil
         
     | 
| 
      
 134 
     | 
    
         
            +
                      matching_apps.each do |a|
         
     | 
| 
      
 135 
     | 
    
         
            +
                        assign_app = a if a[:name] == name
         
     | 
| 
      
 136 
     | 
    
         
            +
                      end
         
     | 
| 
      
 137 
     | 
    
         
            +
                      if assign_app
         
     | 
| 
      
 138 
     | 
    
         
            +
                        display "+> Pairing this repo to deployed app - #{assign_app[:name]}"
         
     | 
| 
      
 139 
     | 
    
         
            +
                        pair_with_remote(assign_app)
         
     | 
| 
      
 140 
     | 
    
         
            +
                        display "+> Repo is now paired to '#{assign_app[:name]}'"
         
     | 
| 
      
 141 
     | 
    
         
            +
                        display
         
     | 
| 
      
 142 
     | 
    
         
            +
                      else
         
     | 
| 
      
 143 
     | 
    
         
            +
                        error "#{name} is not found among your launched app list"
         
     | 
| 
      
 144 
     | 
    
         
            +
                      end
         
     | 
| 
      
 145 
     | 
    
         
            +
                    else
         
     | 
| 
      
 146 
     | 
    
         
            +
                      errors = []
         
     | 
| 
      
 147 
     | 
    
         
            +
                      errors << "Multiple matches found"
         
     | 
| 
      
 148 
     | 
    
         
            +
                      errors << ""
         
     | 
| 
      
 149 
     | 
    
         
            +
                      matching_apps.each do |match|
         
     | 
| 
      
 150 
     | 
    
         
            +
                        errors << "-> #{match[:name]}"
         
     | 
| 
      
 151 
     | 
    
         
            +
                      end
         
     | 
| 
      
 152 
     | 
    
         
            +
                      errors << ""
         
     | 
| 
      
 153 
     | 
    
         
            +
                      errors << "You have more then one app that uses this repo."
         
     | 
| 
      
 154 
     | 
    
         
            +
                      errors << "Please specify which app you would like to pair to."
         
     | 
| 
      
 155 
     | 
    
         
            +
                      errors << ""
         
     | 
| 
      
 156 
     | 
    
         
            +
                      errors << "ex: pagoda pair #{matching_apps[0][:name]}"
         
     | 
| 
      
 157 
     | 
    
         
            +
                      error errors
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  elsif matching_apps.count == 1
         
     | 
| 
      
 160 
     | 
    
         
            +
                    match = matching_apps.first
         
     | 
| 
      
 161 
     | 
    
         
            +
                    display "+> Pairing this repo to deployed app - #{match[:name]}"
         
     | 
| 
      
 162 
     | 
    
         
            +
                    pair_with_remote match
         
     | 
| 
      
 163 
     | 
    
         
            +
                    display "+> Repo is now paired to '#{match[:name]}'"
         
     | 
| 
      
 164 
     | 
    
         
            +
                    display
         
     | 
| 
      
 165 
     | 
    
         
            +
                  else
         
     | 
| 
      
 166 
     | 
    
         
            +
                    error "Current git repo doesn't match any launched app repos"
         
     | 
| 
      
 167 
     | 
    
         
            +
                  end
         
     | 
| 
      
 168 
     | 
    
         
            +
                end
         
     | 
| 
      
 169 
     | 
    
         
            +
                
         
     | 
| 
      
 170 
     | 
    
         
            +
                def unpair
         
     | 
| 
      
 171 
     | 
    
         
            +
                  app
         
     | 
| 
      
 172 
     | 
    
         
            +
                  display
         
     | 
| 
      
 173 
     | 
    
         
            +
                  display "+> Unpairing this repo"
         
     | 
| 
      
 174 
     | 
    
         
            +
                  remove_app(app)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  display "+> Free at last!"
         
     | 
| 
      
 176 
     | 
    
         
            +
                  display
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
                
         
     | 
| 
      
 179 
     | 
    
         
            +
                def deploy
         
     | 
| 
      
 180 
     | 
    
         
            +
                  app
         
     | 
| 
      
 181 
     | 
    
         
            +
                  display
         
     | 
| 
      
 182 
     | 
    
         
            +
                  branch = parse_branch
         
     | 
| 
      
 183 
     | 
    
         
            +
                  commit = parse_commit
         
     | 
| 
      
 184 
     | 
    
         
            +
                  if option_value(nil, "--latest")
         
     | 
| 
      
 185 
     | 
    
         
            +
                    client.deploy_latest(app)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    display "+> deploying to latest commit point on github...", false
         
     | 
| 
      
 187 
     | 
    
         
            +
                    loop_transaction
         
     | 
| 
      
 188 
     | 
    
         
            +
                    display "+> deployed"
         
     | 
| 
      
 189 
     | 
    
         
            +
                    display
         
     | 
| 
      
 190 
     | 
    
         
            +
                  else
         
     | 
| 
      
 191 
     | 
    
         
            +
                    client.deploy(app, branch, commit)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    display "+> deploying to match current branch and commit...", false
         
     | 
| 
      
 193 
     | 
    
         
            +
                    loop_transaction
         
     | 
| 
      
 194 
     | 
    
         
            +
                    display "+> deployed"
         
     | 
| 
      
 195 
     | 
    
         
            +
                    display
         
     | 
| 
      
 196 
     | 
    
         
            +
                  end
         
     | 
| 
      
 197 
     | 
    
         
            +
                end
         
     | 
| 
      
 198 
     | 
    
         
            +
                
         
     | 
| 
      
 199 
     | 
    
         
            +
                def rewind
         
     | 
| 
      
 200 
     | 
    
         
            +
                  app
         
     | 
| 
      
 201 
     | 
    
         
            +
                  display
         
     | 
| 
      
 202 
     | 
    
         
            +
                  transaction = client.rewind(app)
         
     | 
| 
      
 203 
     | 
    
         
            +
                  display "+> undo...", false
         
     | 
| 
      
 204 
     | 
    
         
            +
                  loop_transaction
         
     | 
| 
      
 205 
     | 
    
         
            +
                  display "+> done"
         
     | 
| 
      
 206 
     | 
    
         
            +
                  display
         
     | 
| 
      
 207 
     | 
    
         
            +
                end
         
     | 
| 
      
 208 
     | 
    
         
            +
                alias :rollback :rewind
         
     | 
| 
      
 209 
     | 
    
         
            +
                alias :undo :rewind
         
     | 
| 
      
 210 
     | 
    
         
            +
                
         
     | 
| 
      
 211 
     | 
    
         
            +
                def fast_forward
         
     | 
| 
      
 212 
     | 
    
         
            +
                  app
         
     | 
| 
      
 213 
     | 
    
         
            +
                  display
         
     | 
| 
      
 214 
     | 
    
         
            +
                  transaction = client.fast_forward(app)
         
     | 
| 
      
 215 
     | 
    
         
            +
                  display "+> redo...", false
         
     | 
| 
      
 216 
     | 
    
         
            +
                  loop_transaction
         
     | 
| 
      
 217 
     | 
    
         
            +
                  display "+> done"
         
     | 
| 
      
 218 
     | 
    
         
            +
                  display
         
     | 
| 
      
 219 
     | 
    
         
            +
                end
         
     | 
| 
      
 220 
     | 
    
         
            +
                alias :fastforward :fast_forward
         
     | 
| 
      
 221 
     | 
    
         
            +
                alias :forward :fast_forward
         
     | 
| 
      
 222 
     | 
    
         
            +
                alias :redo :fast_forward
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                protected
         
     | 
| 
      
 225 
     | 
    
         
            +
                
         
     | 
| 
      
 226 
     | 
    
         
            +
                def pair_with_remote(app)
         
     | 
| 
      
 227 
     | 
    
         
            +
                  my_app_list = read_apps
         
     | 
| 
      
 228 
     | 
    
         
            +
                  current_root = locate_app_root
         
     | 
| 
      
 229 
     | 
    
         
            +
                  in_list = false
         
     | 
| 
      
 230 
     | 
    
         
            +
                  my_app_list.each do |app_str|
         
     | 
| 
      
 231 
     | 
    
         
            +
                    app_arr = app_str.split(" ")
         
     | 
| 
      
 232 
     | 
    
         
            +
                    if app[:git_url] == app_arr[1] && app[:name] == app_arr[0] || app_arr[2] == current_root
         
     | 
| 
      
 233 
     | 
    
         
            +
                      in_list = true
         
     | 
| 
      
 234 
     | 
    
         
            +
                    end
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
                  unless in_list
         
     | 
| 
      
 237 
     | 
    
         
            +
                    add_app app[:name]
         
     | 
| 
      
 238 
     | 
    
         
            +
                  end
         
     | 
| 
      
 239 
     | 
    
         
            +
                end
         
     | 
| 
      
 240 
     | 
    
         
            +
                
         
     | 
| 
      
 241 
     | 
    
         
            +
                
         
     | 
| 
      
 242 
     | 
    
         
            +
              end
         
     | 
| 
      
 243 
     | 
    
         
            +
            end
         
     |