deployhq 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 889f38a4af08698a39c5f067aaa861ba7df6ef6b
4
+ data.tar.gz: 77791a4866fb8c7ede8a40f3d843679763e06283
5
+ SHA512:
6
+ metadata.gz: fbb92bf30ef4ec9699c37f2fac34b818a284ca60c8b1dd26b76b874f78402b5af24170f08519247ef30a2547b9b689f2c67e91f8357eff870e92257b2d268fd8
7
+ data.tar.gz: c2901bef7a41b21b7fbb51de8b70790eadd15a71f85ddb112a070c37b14c0b67317c063af0dc8198e5dd6c300104948d880fc81978d96f89a0e9d6ad4b6c518d
data/bin/deployhq ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'deploy/cli'
4
+
5
+ Deploy::CLI.invoke(*ARGV)
data/lib/deploy/cli.rb ADDED
@@ -0,0 +1,194 @@
1
+ require 'optparse'
2
+ require 'highline/import'
3
+ require 'deploy'
4
+
5
+ HighLine.colorize_strings
6
+
7
+ module Deploy
8
+ class CLI
9
+
10
+ ## Constants for formatting output
11
+ TAP_COLOURS = {:info => :yellow, :error => :red, :success => :green}
12
+ PROTOCOL_NAME = {:ssh => "SSH/SFTP", :ftp => "FTP", :s3 => "Amazon S3", :rackspace => "Rackspace CloudFiles"}
13
+
14
+ class Config
15
+ AVAILABLE_CONFIG = [:account, :username, :api_key, :project]
16
+
17
+ def initialize(config_file=nil)
18
+ @config_file_path = config_file || File.join(Dir.pwd, 'Deployfile')
19
+ @config = JSON.parse(File.read(@config_file_path))
20
+ rescue Errno::ENOENT => e
21
+ puts "Couldn't find configuration file at #{@config_file_path}"
22
+ exit 1
23
+ end
24
+
25
+ def method_missing(meth, *args, &block)
26
+ if AVAILABLE_CONFIG.include?(meth.to_sym)
27
+ @config[meth.to_s]
28
+ else
29
+ super
30
+ end
31
+ end
32
+ end
33
+
34
+ class << self
35
+
36
+ def invoke(*args)
37
+ options = {}
38
+ OptionParser.new do |opts|
39
+ opts.banner = "Usage: deployhq [command]"
40
+ opts.on("-c", "--config", 'Configuration file path') do |v|
41
+ options[:config_file] = v
42
+ end
43
+ end.parse!
44
+
45
+ @configuration = Config.new(options[:config_file])
46
+ Deploy.site = @configuration.account
47
+ Deploy.email = @configuration.username
48
+ Deploy.api_key = @configuration.api_key
49
+ @project = Deploy::Project.find(@configuration.project)
50
+
51
+ case args[0]
52
+ when 'deploy'
53
+ deploy
54
+ when 'servers'
55
+ server_list
56
+ else
57
+ puts "Usage: deployhq [command]"
58
+ return
59
+ end
60
+ end
61
+
62
+ def server_list
63
+ @server_groups ||= @project.server_groups
64
+ if @server_groups.count > 0
65
+ @server_groups.each do |group|
66
+ puts "Group: #{group.name}".bold
67
+ puts group.servers.map {|server| format_server(server) }.join("\n\n")
68
+ end
69
+ end
70
+
71
+ @ungrouped_servers ||= @project.servers
72
+ if @ungrouped_servers.count > 0
73
+ puts "\n" if @server_groups.count > 0
74
+ puts "Ungrouped Servers".bold
75
+ puts @ungrouped_servers.map {|server| format_server(server) }.join("\n\n")
76
+ end
77
+ end
78
+
79
+ def deploy
80
+ @ungrouped_servers = @project.servers
81
+ @server_groups = @project.server_groups
82
+
83
+ parent = nil
84
+ while parent.nil?
85
+ parent = choose do |menu|
86
+ menu.prompt = "Please choose a server or group to deploy to:"
87
+
88
+ menu.choices(*(@ungrouped_servers + @server_groups))
89
+ menu.choice("List Server Details") do
90
+ server_list
91
+ nil
92
+ end
93
+ end
94
+ end
95
+
96
+ latest_revision = @project.latest_revision(parent.preferred_branch)
97
+ @deployment = @project.deploy(parent.identifier, parent.last_revision, latest_revision)
98
+
99
+ @server_names = @deployment.servers.each_with_object({}) do |server, hsh|
100
+ hsh[server['id']] = server['name']
101
+ end
102
+ @longest_server_name = @server_names.values.map(&:length).max
103
+
104
+ last_tap = nil
105
+ current_status = 'pending'
106
+ previous_status = ''
107
+ print "Waiting for deployment capacity..."
108
+ while ['running', 'pending'].include?(current_status) do
109
+ sleep 1
110
+
111
+ poll = @deployment.status_poll(:since => last_tap, :status => current_status)
112
+
113
+ # Status only gets returned from the API if it has changed
114
+ current_status = poll.status if poll.status
115
+
116
+ if current_status == 'pending'
117
+ print "."
118
+ elsif current_status == 'running' && previous_status == 'pending'
119
+ puts "\n"
120
+ end
121
+
122
+ if current_status != 'pending'
123
+ poll.taps.each do |tap|
124
+ puts format_tap(tap)
125
+ last_tap = tap.id.to_i
126
+ end
127
+ end
128
+
129
+ previous_status = current_status
130
+ end
131
+ end
132
+
133
+ def deployment
134
+ @deployment = @project.deployments.first
135
+ @server_names = @deployment.servers.each_with_object({}) do |obj, hsh|
136
+ hsh[obj.delete("id")] = obj["name"]
137
+ end
138
+ @longest_server_name = @server_names.values.map(&:length).max
139
+
140
+ @deployment.taps.reverse.each do |tap|
141
+ puts format_tap(tap)
142
+ end
143
+ end
144
+
145
+
146
+ ## Data formatters
147
+
148
+ def format_tap(tap)
149
+ server_name = @server_names[tap.server_id]
150
+
151
+ if server_name
152
+ padding = (@longest_server_name - server_name.length) / 2.0
153
+ server_name = "[#{' ' * padding.ceil} #{server_name} #{' ' * padding.floor}]"
154
+ else
155
+ server_name = ' '
156
+ end
157
+
158
+ text_colour = TAP_COLOURS[tap.tap_type.to_sym] || :white
159
+
160
+ String.new.tap do |s|
161
+ s << "#{server_name} ".color(text_colour, :bold)
162
+ s << tap.message.color(text_colour)
163
+ end
164
+ end
165
+
166
+ def format_server(server)
167
+ server_params = {
168
+ "Name" => server.name,
169
+ "Type" => PROTOCOL_NAME[server.protocol_type.to_sym],
170
+ "Path" => server.server_path,
171
+ "Branch" => server.preferred_branch,
172
+ "Current Revision" => server.last_revision,
173
+ }
174
+ server_params["Hostname"] = [server.hostname, server.port].join(':') if server.hostname
175
+ server_params["Bucket"] = server.bucket_name if server.bucket_name
176
+ server_params["Region"] = server.region if server.region
177
+ server_params["Container"] = server.container_name if server.container_name
178
+
179
+ Array.new.tap do |a|
180
+ a << format_kv_pair(server_params)
181
+ end.join("\n")
182
+ end
183
+
184
+ def format_kv_pair(hash)
185
+ longest_key = hash.keys.map(&:length).max + 2
186
+ hash.each_with_index.map do |(k,v), i|
187
+ str = sprintf("%#{longest_key}s : %s", k,v)
188
+ i == 0 ? str.color(:bold) : str
189
+ end.join("\n")
190
+ end
191
+
192
+ end
193
+ end
194
+ end
@@ -1,19 +1,36 @@
1
1
  module Deploy
2
2
  class Deployment < Base
3
-
3
+
4
4
  class << self
5
5
  def collection_path(params = {})
6
6
  "projects/#{params[:project].permalink}/deployments"
7
7
  end
8
-
8
+
9
9
  def member_path(id, params = {})
10
10
  "projects/#{params[:project].permalink}/deployments/#{id}"
11
11
  end
12
12
  end
13
-
13
+
14
14
  def default_params
15
15
  {:project => self.project}
16
16
  end
17
-
17
+
18
+ def project
19
+ if self.attributes['project'].is_a?(Hash)
20
+ self.attributes['project'] = Project.send(:create_object, self.attributes['project'])
21
+ end
22
+ self.attributes['project']
23
+ end
24
+
25
+ def taps(params={})
26
+ params = {:deployment => self, :project => self.project}.merge(params)
27
+ DeploymentTap.find(:all, params)
28
+ end
29
+
30
+ def status_poll(params = {})
31
+ params = {:deployment => self, :project => self.project}.merge(params)
32
+ DeploymentStatusPoll.poll(params)
33
+ end
34
+
18
35
  end
19
- end
36
+ end
@@ -0,0 +1,34 @@
1
+ module Deploy
2
+ class DeploymentStatusPoll
3
+ attr_accessor :attributes
4
+
5
+ def initialize(parsed_json)
6
+ self.attributes = parsed_json
7
+ end
8
+
9
+ def status
10
+ @status ||= attributes['status']
11
+ end
12
+
13
+ def taps
14
+ return [] unless attributes['taps']
15
+ @taps ||= attributes['taps'].map { |t| DeploymentTap.send(:create_object, t) }
16
+ end
17
+
18
+ class << self
19
+ def poll_url(params)
20
+ base = "projects/#{params[:project].permalink}/deployments/#{params[:deployment].identifier}/logs/poll"
21
+ base += "?status=#{params[:status]}"
22
+ base += "&since=#{params[:since]}" if params[:since]
23
+ base
24
+ end
25
+
26
+ def poll(params = {})
27
+ req = Request.new(poll_url(params)).make
28
+ parsed = JSON.parse(req.output)
29
+
30
+ new(parsed)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ module Deploy
2
+ class DeploymentTap < Base
3
+
4
+ class << self
5
+ def collection_path(params = {})
6
+ base = "projects/#{params[:project].permalink}/deployments/#{params[:deployment].identifier}.js"
7
+ base += "?since=#{params[:since]}" if params[:since]
8
+ base
9
+ end
10
+ end
11
+
12
+ def default_params
13
+ {:deployment => self.deployment, :project => self.deployment.project}
14
+ end
15
+
16
+ end
17
+ end
@@ -1,23 +1,30 @@
1
1
  module Deploy
2
2
  class Project < Base
3
-
3
+
4
4
  ## Return all deployments for this project
5
5
  def deployments
6
6
  Deployment.find(:all, :project => self)
7
7
  end
8
-
8
+
9
9
  ## Return a deployment
10
10
  def deployment(identifier)
11
11
  Deployment.find(identifier, :project => self)
12
12
  end
13
-
13
+
14
+ def latest_revision(branch = '')
15
+ branch ||= 'master'
16
+ req = Request.new(self.class.member_path(self.permalink) + "/repository/latest_revision?branch=#{branch}").make
17
+ parsed = JSON.parse(req.output)
18
+ parsed['ref']
19
+ end
20
+
14
21
  ## Create a deployment in this project (and queue it to run)
15
22
  def deploy(server, start_revision, end_revision)
16
23
  run_deployment(server, start_revision, end_revision) do |d|
17
24
  d.mode = 'queue'
18
25
  end
19
26
  end
20
-
27
+
21
28
  ##
22
29
  def preview(server, start_revision, end_revision)
23
30
  run_deployment(server, start_revision, end_revision) do |d|
@@ -29,9 +36,13 @@ module Deploy
29
36
  def servers
30
37
  Server.find(:all, :project => self)
31
38
  end
32
-
39
+
40
+ def server_groups
41
+ ServerGroup.find(:all, :project => self)
42
+ end
43
+
33
44
  private
34
-
45
+
35
46
  def run_deployment(server, start_revision, end_revision, &block)
36
47
  d = Deployment.new
37
48
  d.project = self
@@ -44,6 +55,6 @@ module Deploy
44
55
  d.save
45
56
  d
46
57
  end
47
-
58
+
48
59
  end
49
- end
60
+ end
@@ -21,7 +21,7 @@ module Deploy
21
21
  ## Hashes will be converted to JSON before being sent to the remote service.
22
22
  def make
23
23
  uri = URI.parse([Deploy.site, @path].join('/'))
24
- http_request = http_class.new(uri.path)
24
+ http_request = http_class.new(uri.request_uri)
25
25
  http_request.basic_auth(Deploy.email, Deploy.api_key)
26
26
  http_request["Accept"] = "application/json"
27
27
  http_request["Content-type"] = "application/json"
data/lib/deploy/server.rb CHANGED
@@ -14,6 +14,18 @@ module Deploy
14
14
  def default_params
15
15
  {:project => self.project}
16
16
  end
17
+
18
+ def to_s
19
+ Array.new.tap do |a|
20
+ a << self.name
21
+ a << "(branch: #{self.preferred_branch})" if self.preferred_branch
22
+ if self.last_revision
23
+ a << "(currently: #{self.last_revision})"
24
+ else
25
+ a << "(currently undeployed)"
26
+ end
27
+ end.join(' ')
28
+ end
17
29
 
18
30
  end
19
31
  end
@@ -0,0 +1,35 @@
1
+ module Deploy
2
+ class ServerGroup < Base
3
+
4
+ class << self
5
+ def collection_path(params = {})
6
+ "projects/#{params[:project].permalink}/server_groups"
7
+ end
8
+
9
+ def member_path(id, params = {})
10
+ "projects/#{params[:project].permalink}/server_groups/#{identifier}"
11
+ end
12
+ end
13
+
14
+ def default_params
15
+ {:project => self.project}
16
+ end
17
+
18
+ def servers
19
+ @servers ||= self.attributes['servers'].map {|server_attr| Deploy::Server.send(:create_object, server_attr) }
20
+ end
21
+
22
+ def to_s
23
+ Array.new.tap do |a|
24
+ a << self.name
25
+ a << "(branch: #{self.preferred_branch})" if self.preferred_branch
26
+ if self.last_revision
27
+ a << "(currently: #{self.last_revision})"
28
+ else
29
+ a << "(currently undeployed)"
30
+ end
31
+ end.join(' ')
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Deploy
2
+ VERSION = "1.3.0"
3
+ end
data/lib/deploy.rb CHANGED
@@ -17,12 +17,14 @@ require 'deploy/base'
17
17
 
18
18
  require 'deploy/project'
19
19
  require 'deploy/deployment'
20
+ require 'deploy/deployment_tap'
21
+ require 'deploy/deployment_status_poll'
20
22
  require 'deploy/server'
23
+ require 'deploy/server_group'
24
+ require 'deploy/version'
21
25
 
22
26
 
23
27
  module Deploy
24
- VERSION = '1.0.0'
25
-
26
28
  class << self
27
29
  ## Domain which you wish to access (e.g. atech.deployhq.com)
28
30
  attr_accessor :site
metadata CHANGED
@@ -1,67 +1,87 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deployhq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
5
- prerelease:
4
+ version: 1.3.0
6
5
  platform: ruby
7
6
  authors:
8
- - Adam Cooke
7
+ - Dan Wentworth
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-09-03 00:00:00.000000000 Z
11
+ date: 2016-04-14 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: json
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 1.4.6
19
+ version: '1.8'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 1.4.6
30
- description:
31
- email: adam@atechmedia.com
32
- executables: []
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: highline
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ description: |2
42
+ API and CLI client for the DeployHQ deployment platform. Provides the
43
+ deployhq executable.
44
+ email: dan@atech.io
45
+ executables:
46
+ - deployhq
33
47
  extensions: []
34
48
  extra_rdoc_files: []
35
49
  files:
50
+ - bin/deployhq
51
+ - lib/deploy.rb
36
52
  - lib/deploy/base.rb
53
+ - lib/deploy/cli.rb
37
54
  - lib/deploy/deployment.rb
55
+ - lib/deploy/deployment_status_poll.rb
56
+ - lib/deploy/deployment_tap.rb
38
57
  - lib/deploy/errors.rb
39
58
  - lib/deploy/project.rb
40
59
  - lib/deploy/request.rb
41
60
  - lib/deploy/server.rb
42
- - lib/deploy.rb
43
- homepage: http://www.deployhq.com
44
- licenses: []
61
+ - lib/deploy/server_group.rb
62
+ - lib/deploy/version.rb
63
+ homepage: https://www.deployhq.com
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
45
67
  post_install_message:
46
68
  rdoc_options: []
47
69
  require_paths:
48
70
  - lib
49
71
  required_ruby_version: !ruby/object:Gem::Requirement
50
- none: false
51
72
  requirements:
52
- - - ! '>='
73
+ - - ">="
53
74
  - !ruby/object:Gem::Version
54
75
  version: '0'
55
76
  required_rubygems_version: !ruby/object:Gem::Requirement
56
- none: false
57
77
  requirements:
58
- - - ! '>='
78
+ - - ">="
59
79
  - !ruby/object:Gem::Version
60
80
  version: '0'
61
81
  requirements: []
62
82
  rubyforge_project:
63
- rubygems_version: 1.8.24
83
+ rubygems_version: 2.4.5.1
64
84
  signing_key:
65
- specification_version: 3
66
- summary: API client for the DeployHQ deployment platform
85
+ specification_version: 4
86
+ summary: API and CLI client for the DeployHQ
67
87
  test_files: []