phase 0.0.17 → 1.0.0.rc1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86303d226d273b681f3cee115252b999fdff08f3
4
- data.tar.gz: 8b6762e471c86eaf776ecaf5fa6ab87346b28d84
3
+ metadata.gz: 9418e0cabac33009818c8d089c896b5b4cb81004
4
+ data.tar.gz: b7346fdc18bcad141314d0e96247e6bb9e3aaf55
5
5
  SHA512:
6
- metadata.gz: 00a2ff363da264cdcd570c3ca42fe70062efe39d02853c90b4ac9867a2fd6a8faac32d336afccd6f41fe2233169a55a865028a410c0370977b00375e73668fee
7
- data.tar.gz: b04c21f1298172bef6bff6efa074d3fa7776ecd460c165429ed7040c0e6140e662d10fb58ad70bb685f2f08f645fd8786445017f0eabda087828ff14728cbe3d
6
+ metadata.gz: 94f9716929b4f0b402104f6c9012300664dde3c1e35df93bd914aa84ed4fbd236f59534f062648a56bc768e745369ea0d3ea0fefcd8dd6aeaaa8ee7eb1860026
7
+ data.tar.gz: 15248f3be2d0e843db4f9778421715204d965af8d1822113f104aea05f081c7304808f96e0d95a6d9221084aeaba267baf8a885064ba8d592b0fa89726da372f
@@ -27,9 +27,8 @@ module Phase
27
27
 
28
28
  def run
29
29
  version_number = get_next_version_number
30
- ::Phase::Deploy::Version.update(version_number) if clean_build
31
30
 
32
- build = ::Phase::Deploy::Build.new(version_number, clean: clean_build)
31
+ build = ::Phase::Deploy::Build.new(version_number, clean_build: clean_build)
33
32
  build.execute!
34
33
  end
35
34
 
@@ -41,7 +40,7 @@ module Phase
41
40
  log "Last release was version #{ current_version.magenta }." if current_version
42
41
 
43
42
  input = ask "New version number:"
44
- fail "version number is required" if input.blank?
43
+ fail "Version number is required" if input.blank?
45
44
  input
46
45
  end
47
46
 
data/lib/phase/cli/ssh.rb CHANGED
@@ -2,7 +2,7 @@ module Phase
2
2
  module CLI
3
3
  class SSH < Command
4
4
  command :ssh do |c|
5
- c.syntax = "phase ssh [-i instance_id] [-n instance_name] [-r instance_role] [-u user] [-c conn_str] [username@instance_name|instance_id]"
5
+ c.syntax = "phase ssh [-i instance_id] [-n instance_name] [-r instance_role] [-u user] [-c conn_str] [username@instance_name|instance_id] [command...]"
6
6
 
7
7
  c.option "-i", "--id instance_id", String, "Connects to the instance with this ID."
8
8
  c.option "-n", "--name instance_name", String, "Connects to the instance with this 'Name' tag."
@@ -21,8 +21,15 @@ module Phase
21
21
 
22
22
  def run
23
23
  parse_connection_string
24
- log "connecting to instance #{ instance.resource.id }..."
25
- exec "#{ options.conn } #{ username }@#{ instance.resource.dns_name }"
24
+ ssh_command = args.last if args.count > 1
25
+
26
+ if ssh_command
27
+ log "running on instance #{ instance.resource.id }: `#{ ssh_command }'"
28
+ exec "#{ options.conn } #{ username }@#{ instance.resource.dns_name } #{ ssh_command }"
29
+ else
30
+ log "connecting to instance #{ instance.resource.id }..."
31
+ exec "#{ options.conn } #{ username }@#{ instance.resource.dns_name }"
32
+ end
26
33
  end
27
34
 
28
35
  private
@@ -19,6 +19,12 @@ module Phase
19
19
  attr_accessor :version_lockfile
20
20
 
21
21
 
22
+ # @return [String] the cloud storage bucket ("directory") for storing compiled assets
23
+ # @example Sample settings
24
+ # config.deploy.docker_repository = "static-assets"
25
+ attr_accessor :asset_bucket
26
+
27
+
22
28
  def initialize
23
29
  @environments = []
24
30
  @version_lockfile = "VERSION"
@@ -4,13 +4,13 @@ module Phase
4
4
  class Build
5
5
  include ::Phase::Util::Shell
6
6
 
7
- attr_reader :build_dir, :clean, :version_tag
7
+ attr_reader :build_dir, :clean_build, :version_tag
8
8
 
9
9
  def initialize(version_tag, options = {})
10
- @clean = options.fetch(:clean, true)
10
+ @clean_build = options.fetch(:clean_build, true)
11
11
  @version_tag = version_tag
12
12
 
13
- if clean
13
+ if clean_build
14
14
  @build_dir = ::Pathname.new( options.fetch(:build_dir, "build") )
15
15
  else
16
16
  @build_dir = ::Pathname.new(".")
@@ -18,29 +18,45 @@ module Phase
18
18
  end
19
19
 
20
20
  def execute!
21
- check_environment
21
+ prepare_environment
22
+ build_assets
23
+ commit_new_version!
22
24
  build_image
23
- # tag_image
24
25
  push
25
26
  end
26
27
 
27
28
  private
28
29
 
30
+ def build_assets
31
+ precompile_assets
32
+ sync_assets
33
+ end
34
+
29
35
  def build_image
30
- prepare_clean_build if clean
36
+ prepare_clean_build if clean_build
31
37
 
32
- shell("docker build -t #{repo_name}:#{version_tag} #{build_dir}") do |status|
38
+ shell("docker build -t #{docker_repo}:#{version_tag} #{build_dir}") do |status|
33
39
  fail "Couldn't build Docker image"
34
40
  end
35
41
  end
36
42
 
37
- def check_environment
43
+ def commit_new_version!
44
+ ::Phase::Deploy::Version.update(version_tag)
45
+ shell("git add -f public/assets/*manifest* #{::Phase.config.deploy.version_lockfile}", allow_failure: true)
46
+ shell("git commit -m 'Built v#{version_tag}'", allow_failure: true)
47
+ end
48
+
49
+ def prepare_environment
50
+ raise_on_dirty_index!
51
+
38
52
  shell("docker ps > /dev/null 2>&1") do |status|
39
53
  fail <<-EOS.strip_heredoc
40
54
  Docker isn't responding. Is boot2docker running? Try:
41
55
  boot2docker start && $(boot2docker shellinit)
42
56
  EOS
43
57
  end
58
+
59
+ pull_latest_build
44
60
  end
45
61
 
46
62
  def clone_local_git_repo
@@ -50,40 +66,62 @@ module Phase
50
66
  end
51
67
  end
52
68
 
69
+ def docker_repo
70
+ ::Phase.config.deploy.docker_repository
71
+ end
72
+
53
73
  def last_committed_mtime_for_file(file_path)
54
74
  rev_hash = `git rev-list HEAD "#{file_path}" | head -n 1`.chomp
55
75
  time_str = `git show --pretty=format:%ai --abbrev-commit #{rev_hash} | head -n 1`.chomp
56
76
  ::DateTime.parse(time_str).to_time
57
77
  end
58
78
 
79
+ # FIXME: This approach isn't ideal because it compiles assets in the *working* git
80
+ # directory rather than building in a clean, committed environment. This could lead
81
+ # to errors in the compiled assets.
82
+ def precompile_assets
83
+ shell("RAILS_GROUPS=assets rake assets:precompile") do |status|
84
+ fail "Couldn't precompile assets"
85
+ end
86
+ end
87
+
59
88
  def prepare_clean_build
60
89
  remove_stale_build_dir!
61
90
  clone_local_git_repo
62
91
  set_file_modification_timestamps
63
92
  end
64
93
 
94
+ # This needs to run *before* the version gets updated so we know which version
95
+ # number to pull from the registry.
96
+ def pull_latest_build
97
+ shell("docker pull #{docker_repo}:#{::Phase::Deploy::Version.current}")
98
+ end
99
+
65
100
  def push
66
- shell("docker push #{repo_name}:#{version_tag}") do |status|
67
- fail "Couldn't push #{repo_name}:#{version_tag}"
101
+ shell("docker push #{docker_repo}:#{version_tag}") do |status|
102
+ fail "Couldn't push #{docker_repo}:#{version_tag}"
68
103
  end
69
104
  end
70
105
 
71
- def remove_stale_build_dir!
72
- ::FileUtils.rm_rf(build_dir)
106
+ def raise_on_dirty_index!
107
+ shell('git diff-index --quiet --cached HEAD') do |status|
108
+ fail "Other changes are already staged. Commit or stash them first"
109
+ end
73
110
  end
74
111
 
75
- def repo_name
76
- ::Phase.config.deploy.docker_repository
112
+ def remove_stale_build_dir!
113
+ ::FileUtils.rm_rf(build_dir)
77
114
  end
78
115
 
79
116
  def set_file_modification_timestamps
80
- log "Preparing docker cache..."
117
+ log("Preparing docker cache...")
81
118
 
119
+ # Threadsafe queue for multiple threads to pull from
82
120
  queue = ::Queue.new
83
121
 
84
122
  ::FileUtils.cd(build_dir) do
85
- # Sets consistent mtime on directories because docker cares about that
86
- system("find . -type d | xargs touch -t 7805200000")
123
+ # Sets consistent mtime on directories because docker cares about that too
124
+ shell("find . -type d | xargs touch -t 7805200000")
87
125
 
88
126
  files = `git ls-files`.split
89
127
  files.each { |f| queue.push(f) }
@@ -106,6 +144,15 @@ module Phase
106
144
  bar.finish
107
145
  end
108
146
  end
147
+
148
+ def sync_assets
149
+ bucket = ::Phase.config.deploy.asset_bucket
150
+ return log("Set `deploy.asset_bucket` in Phasefile to enable asset syncing") if bucket.blank?
151
+
152
+ shell("RAILS_GROUPS=assets FOG_DIRECTORY=#{bucket} rake assets:sync") do |status|
153
+ fail "Couldn't sync assets to The Clouds"
154
+ end
155
+ end
109
156
  end
110
157
 
111
158
  end
@@ -15,7 +15,6 @@ module Phase
15
15
 
16
16
  # Prints a message and then exits.
17
17
  def fail(str)
18
- puts
19
18
  abort "[phase]".red + " #{ str }"
20
19
  end
21
20
 
@@ -4,10 +4,17 @@ module Phase
4
4
  include Console
5
5
 
6
6
  def shell(*args)
7
+ options = args.extract_options!
8
+ options.reverse_merge({
9
+ allow_failure: false
10
+ })
11
+
7
12
  log "running: #{args.join(' ')}"
8
- status = !!system(*args)
9
- yield $? unless status
10
- return status
13
+ succeeded = !!system(*args) || options[:allow_failure]
14
+
15
+ yield $? unless succeeded
16
+
17
+ succeeded
11
18
  end
12
19
 
13
20
  end
data/lib/phase/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Phase
2
- VERSION = "0.0.17"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piers Mainwaring
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-12 00:00:00.000000000 Z
12
+ date: 2015-06-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: commander
@@ -256,9 +256,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
256
256
  version: '2.0'
257
257
  required_rubygems_version: !ruby/object:Gem::Requirement
258
258
  requirements:
259
- - - ">="
259
+ - - ">"
260
260
  - !ruby/object:Gem::Version
261
- version: '0'
261
+ version: 1.3.1
262
262
  requirements: []
263
263
  rubyforge_project:
264
264
  rubygems_version: 2.2.3