capistrano-hivequeen 0.5.0 → 0.6.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.
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  ## If your rubyforge_project name is different, then edit it and comment out
7
7
  ## the sub! line in the Rakefile
8
8
  s.name = 'capistrano-hivequeen'
9
- s.version = '0.5.0'
9
+ s.version = '0.6.0'
10
10
  s.date = Time.now.strftime("%Y-%m-%d")
11
11
 
12
12
  ## Make sure your summary is short. The description may be as long
@@ -16,6 +16,10 @@ Capistrano::Configuration.instance(:must_exist).load do
16
16
  set :repository, HiveQueen.repository
17
17
  set :scm, :git
18
18
 
19
+ # By default, don't override deployments if there's another deployment in progress.
20
+ # From the command line, use -s override=true to force a deployment
21
+ set :override, false
22
+
19
23
  # Load capistrano multi-stage extension
20
24
  require 'fileutils' # required until https://github.com/capistrano/capistrano-ext/commit/930ca840a0b4adad0ec53546790b3f5ffe726538 is released
21
25
  require 'capistrano/ext/multistage'
@@ -8,6 +8,28 @@ Capistrano::Configuration.instance.load do
8
8
  end
9
9
  end
10
10
 
11
+ before "deploy:update", "hivequeen:start"
12
+ before "setup", "hivequeen:start"
13
+ namespace :hivequeen do
14
+ desc "[internal] Start a deployment in hivequeen"
15
+ task :start do
16
+ # TODO: is there a better way to determine what cap tasks are running?
17
+ tasks = ARGV.reject{|task_name| stage.to_s == task_name}
18
+ params = {
19
+ :task => tasks.join(' '),
20
+ :commit => real_revision,
21
+ :override => override
22
+ }
23
+ begin
24
+ deployment = HiveQueen.start_deployment(environment_id, params)
25
+ set :deployment_id, deployment['id']
26
+ at_exit { HiveQueen.finish_deployment(environment_id, deployment['id']) }
27
+ rescue HiveQueen::DeploymentError
28
+ abort "Cannot start deployment. Errors: #{$!.message}"
29
+ end
30
+ end
31
+ end
32
+
11
33
  desc "Deploy without migrations"
12
34
  task(:hotfix) { deploy.default }
13
35
 
@@ -8,11 +8,14 @@ require 'base64'
8
8
  # - environment not found
9
9
  # - environment not ready: fail
10
10
  class HiveQueen
11
+ class DeploymentError < Exception; end
12
+ class InsecureCredentials < Exception; end
13
+
11
14
  class << self
12
15
  attr_accessor :endpoint, :logger, :project, :username, :password
13
16
 
14
17
  def project_data
15
- @project_data ||= fetch("/projects/#{project}.json")
18
+ @project_data ||= get("/projects/#{project}.json")
16
19
  end
17
20
 
18
21
  def environments
@@ -30,18 +33,40 @@ class HiveQueen
30
33
  def roles(env_id)
31
34
  env_id = env_id.to_sym
32
35
  @roles ||= {}
33
- @roles[env_id] ||= fetch("/environments/#{env_id}.json")
36
+ @roles[env_id] ||= get("/environments/#{env_id}.json")
37
+ end
38
+
39
+ def start_deployment(environment_id, params)
40
+ required_params = [:task, :commit]
41
+ required_params.each do |key|
42
+ raise ArgumentError.new("#{key} is a required param") unless params.key?(key)
43
+ end
44
+ put_or_post('POST', "/environments/#{environment_id}/deployments.json", :deployment => params)
45
+ end
46
+
47
+ def finish_deployment(environment_id, deployment_id)
48
+ state = $! ? 'failed' : 'succeeded'
49
+ puts "Finishing deployment in Hivequeen. State: #{state}"
50
+ params = {:deployment => {:state => state}}
51
+ put_or_post('PUT', "/environments/#{environment_id}/deployments/#{deployment_id}.json", params)
34
52
  end
35
53
 
36
54
  # Load credentials from ~/.hivequeen
37
55
  def get_credentials!
38
56
  @username, @password = File.read(credential_path).chomp.split(':')
39
57
  raise unless username && password
58
+ # Check that credentials are not accessible to world or group
59
+ mode = File.stat(credential_path).mode
60
+ raise InsecureCredentials unless (mode % 64 == 0)
61
+ rescue InsecureCredentials
62
+ puts "#{credential_path} is insecure. Please change you password and run"
63
+ puts "chmod 600 #{credential_path}"
64
+ exit 1
40
65
  rescue Errno::ENOENT, RuntimeError
41
66
  puts "Could not read HiveQueen credentials from #{credential_path}."
42
67
  puts "#{credential_path} should contain your username and password seperated by a colon"
43
68
  puts "Run this command with your credentials:"
44
- puts " $ echo username:password > #{credential_path}"
69
+ puts " $ echo username:password > #{credential_path}; chmod 600 #{credential_path}"
45
70
  exit 1
46
71
  end
47
72
 
@@ -59,7 +84,7 @@ class HiveQueen
59
84
  { 'Authorization' => "Basic #{value}" }
60
85
  end
61
86
 
62
- def fetch(path)
87
+ def get(path)
63
88
  url = "#{endpoint}#{path}"
64
89
  logger.trace "Fetching #{url}"
65
90
  response = connection.request(:method => 'GET', :path => path, :headers => auth_header)
@@ -69,5 +94,19 @@ class HiveQueen
69
94
  JSON.parse(response.body)
70
95
  end
71
96
 
97
+ def put_or_post(method, path, data)
98
+ headers = auth_header.merge("Content-type"=>"application/json", "Accept"=>"application/json")
99
+ response = connection.request(:path => path, :method => method, :headers => headers, :body => data.to_json)
100
+ case response.status
101
+ when (200..299)
102
+ JSON.parse(response.body)
103
+ when (400..499)
104
+ errors = JSON.parse(response.body)
105
+ raise DeploymentError.new(errors.inspect)
106
+ else
107
+ raise "Request to #{path} returned #{response.status} status"
108
+ end
109
+ end
110
+
72
111
  end
73
112
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-hivequeen
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Aaron Suggs
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-18 00:00:00 -04:00
18
+ date: 2011-10-20 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency