phase 0.0.16.1 → 0.0.17

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: d5ebb4484b885d8dad52f7413fdaf3c50929d193
4
- data.tar.gz: 55d319392ca5d5056f071e05831c951f15a59395
3
+ metadata.gz: 86303d226d273b681f3cee115252b999fdff08f3
4
+ data.tar.gz: 8b6762e471c86eaf776ecaf5fa6ab87346b28d84
5
5
  SHA512:
6
- metadata.gz: 6553814d3f824afe7db88505de68b74dfdc07c8468568ec671512552771684bfb764af74856351dcd5cc02051d703da7d1a7be8a8c3812683b941bed5043a49d
7
- data.tar.gz: 2e1476f1da9b4f3a8088074c049bb9326ceb4323f2f8b7ece9e4e1bf2de07ec06574047d22a2b4444678eb17eaff0b8e97c604ec2e6c347611a4640250f162f4
6
+ metadata.gz: 00a2ff363da264cdcd570c3ca42fe70062efe39d02853c90b4ac9867a2fd6a8faac32d336afccd6f41fe2233169a55a865028a410c0370977b00375e73668fee
7
+ data.tar.gz: b04c21f1298172bef6bff6efa074d3fa7776ecd460c165429ed7040c0e6140e662d10fb58ad70bb685f2f08f645fd8786445017f0eabda087828ff14728cbe3d
@@ -3,7 +3,9 @@ module Phase
3
3
  class Build < Command
4
4
 
5
5
  command :build do |c|
6
- c.syntax = "phase build <version_number>"
6
+ c.syntax = "phase build [-s]"
7
+
8
+ c.option "-s", "--sandbox", String, "Build in sandbox mode: uses current directory's possibly dirty git tree as build context."
7
9
 
8
10
  c.description = <<-EOS.strip_heredoc
9
11
  Builds a new Docker image of the latest committed code on the current branch. Tags the
@@ -11,25 +13,38 @@ module Phase
11
13
  EOS
12
14
 
13
15
  c.action do |args, options|
16
+ options.default(sandbox: false)
14
17
  new(args, options).run
15
18
  end
16
19
  end
17
20
 
18
- attr_reader :version_number
21
+ attr_reader :clean_build, :version_number
19
22
 
20
23
  def initialize(args, options)
21
24
  super
22
-
23
- @version_number = args[0]
24
-
25
- fail "must specify version number" unless version_number
25
+ @clean_build = !options.sandbox
26
26
  end
27
27
 
28
28
  def run
29
- build = ::Phase::Deploy::Build.new(version_number)
29
+ version_number = get_next_version_number
30
+ ::Phase::Deploy::Version.update(version_number) if clean_build
31
+
32
+ build = ::Phase::Deploy::Build.new(version_number, clean: clean_build)
30
33
  build.execute!
31
34
  end
32
35
 
36
+ private
37
+
38
+ def get_next_version_number
39
+ current_version = ::Phase::Deploy::Version.current
40
+
41
+ log "Last release was version #{ current_version.magenta }." if current_version
42
+
43
+ input = ask "New version number:"
44
+ fail "version number is required" if input.blank?
45
+ input
46
+ end
47
+
33
48
  end
34
49
  end
35
50
  end
@@ -13,8 +13,15 @@ module Phase
13
13
  attr_accessor :docker_repository
14
14
 
15
15
 
16
+ # @return [String] the path (relative to Phasefile) to the version lockfile (default "VERSION")
17
+ # @example Sample settings
18
+ # config.deploy.version_lockfile = "lib/myproj/version.lock"
19
+ attr_accessor :version_lockfile
20
+
21
+
16
22
  def initialize
17
23
  @environments = []
24
+ @version_lockfile = "VERSION"
18
25
  end
19
26
 
20
27
  # Adds a new deployment environment.
@@ -4,14 +4,21 @@ module Phase
4
4
  class Build
5
5
  include ::Phase::Util::Shell
6
6
 
7
- attr_reader :version_tag, :build_dir
7
+ attr_reader :build_dir, :clean, :version_tag
8
8
 
9
9
  def initialize(version_tag, options = {})
10
+ @clean = options.fetch(:clean, true)
10
11
  @version_tag = version_tag
11
- @build_dir = ::Pathname.new( options.fetch(:build_dir, "build") )
12
+
13
+ if clean
14
+ @build_dir = ::Pathname.new( options.fetch(:build_dir, "build") )
15
+ else
16
+ @build_dir = ::Pathname.new(".")
17
+ end
12
18
  end
13
19
 
14
20
  def execute!
21
+ check_environment
15
22
  build_image
16
23
  # tag_image
17
24
  push
@@ -20,40 +27,45 @@ module Phase
20
27
  private
21
28
 
22
29
  def build_image
23
- prepare_build
30
+ prepare_clean_build if clean
24
31
 
25
32
  shell("docker build -t #{repo_name}:#{version_tag} #{build_dir}") do |status|
26
- fail "couldn't build Docker image"
33
+ fail "Couldn't build Docker image"
34
+ end
35
+ end
36
+
37
+ def check_environment
38
+ shell("docker ps > /dev/null 2>&1") do |status|
39
+ fail <<-EOS.strip_heredoc
40
+ Docker isn't responding. Is boot2docker running? Try:
41
+ boot2docker start && $(boot2docker shellinit)
42
+ EOS
27
43
  end
28
44
  end
29
45
 
30
46
  def clone_local_git_repo
31
47
  current_branch = `git rev-parse --abbrev-ref HEAD`.strip
32
- shell("git clone --reference $(pwd) --branch #{current_branch} --depth 1 -- file://$(pwd) #{build_dir}") do |status|
33
- fail "couldn't clone local copy of git repository"
48
+ shell("git clone --reference $(pwd) --branch #{current_branch} -- file://$(pwd) #{build_dir}") do |status|
49
+ fail "Couldn't clone local copy of git repository"
34
50
  end
35
51
  end
36
52
 
37
- def prepare_build
53
+ def last_committed_mtime_for_file(file_path)
54
+ rev_hash = `git rev-list HEAD "#{file_path}" | head -n 1`.chomp
55
+ time_str = `git show --pretty=format:%ai --abbrev-commit #{rev_hash} | head -n 1`.chomp
56
+ ::DateTime.parse(time_str).to_time
57
+ end
58
+
59
+ def prepare_clean_build
38
60
  remove_stale_build_dir!
39
61
  clone_local_git_repo
40
62
  set_file_modification_timestamps
41
63
  end
42
64
 
43
- # def tag_image
44
- # shell("docker tag #{repo_name}:#{version_tag} #{repo_name}:latest") do |status|
45
- # fail "couldn't tag Docker image"
46
- # end
47
- # end
48
-
49
65
  def push
50
66
  shell("docker push #{repo_name}:#{version_tag}") do |status|
51
- fail "couldn't push #{repo_name}:#{version_tag}"
67
+ fail "Couldn't push #{repo_name}:#{version_tag}"
52
68
  end
53
-
54
- # shell("docker push #{repo_name}:latest") do |status|
55
- # fail "couldn't push #{repo_name}:latest"
56
- # end
57
69
  end
58
70
 
59
71
  def remove_stale_build_dir!
@@ -65,7 +77,34 @@ module Phase
65
77
  end
66
78
 
67
79
  def set_file_modification_timestamps
68
-
80
+ log "Preparing docker cache..."
81
+
82
+ queue = ::Queue.new
83
+
84
+ ::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")
87
+
88
+ files = `git ls-files`.split
89
+ files.each { |f| queue.push(f) }
90
+
91
+ bar = ::ProgressBar.new("Setting mtimes", files.count)
92
+
93
+ threads = 4.times.map do |idx|
94
+ ::Thread.new do
95
+ begin
96
+ while path = queue.pop(true)
97
+ ::FileUtils.touch(path, mtime: last_committed_mtime_for_file(path))
98
+ bar.inc
99
+ end
100
+ rescue ThreadError
101
+ end
102
+ end
103
+ end
104
+
105
+ threads.each(&:join)
106
+ bar.finish
107
+ end
69
108
  end
70
109
  end
71
110
 
@@ -0,0 +1,29 @@
1
+ module Phase
2
+ module Deploy
3
+
4
+ class Version
5
+ class << self
6
+
7
+ def current
8
+ ::File.read( ::Phase.config.deploy.version_lockfile ).chomp rescue nil
9
+ end
10
+
11
+ def next
12
+ current.to_i + 1
13
+ end
14
+
15
+ def update(new_version)
16
+ write_version(new_version)
17
+ end
18
+
19
+ private
20
+
21
+ def write_version(new_version)
22
+ ::File.open( ::Phase.config.deploy.version_lockfile, 'w' ) { |f| f.write(new_version) }
23
+ end
24
+
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -2,10 +2,18 @@ module Phase
2
2
  module Util
3
3
  module Console
4
4
 
5
+ # Prompts user for input.
6
+ def ask(str)
7
+ print "[phase] ".blue.on_cyan + "#{str}".black.on_cyan + " "
8
+ STDIN.gets.chomp
9
+ end
10
+
11
+ # Prints a message.
5
12
  def log(str)
6
13
  puts "[phase]".green + " #{ str }"
7
14
  end
8
15
 
16
+ # Prints a message and then exits.
9
17
  def fail(str)
10
18
  puts
11
19
  abort "[phase]".red + " #{ str }"
data/lib/phase/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Phase
2
- VERSION = "0.0.16.1"
2
+ VERSION = "0.0.17"
3
3
  end
data/lib/phase.rb CHANGED
@@ -7,6 +7,8 @@ require 'progressbar'
7
7
  require 'sshkit'
8
8
  require 'terminal-table'
9
9
 
10
+ require 'pry'
11
+
10
12
 
11
13
  require 'phase/adapter'
12
14
  require 'phase/adapters/abstract'
@@ -17,6 +19,7 @@ require "phase/util/shell"
17
19
 
18
20
  require 'phase/kit/deploy/build'
19
21
  require 'phase/kit/deploy/deployment'
22
+ require 'phase/kit/deploy/version'
20
23
 
21
24
  require 'phase/kit/ipa/app'
22
25
  require 'phase/kit/ipa/enterprise_deployment'
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.16.1
4
+ version: 0.0.17
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-05-29 00:00:00.000000000 Z
12
+ date: 2015-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: commander
@@ -225,6 +225,7 @@ files:
225
225
  - lib/phase/dsl.rb
226
226
  - lib/phase/kit/deploy/build.rb
227
227
  - lib/phase/kit/deploy/deployment.rb
228
+ - lib/phase/kit/deploy/version.rb
228
229
  - lib/phase/kit/ipa/app.rb
229
230
  - lib/phase/kit/ipa/enterprise_deployment.rb
230
231
  - lib/phase/kit/keys/key.rb
@@ -260,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
260
261
  version: '0'
261
262
  requirements: []
262
263
  rubyforge_project:
263
- rubygems_version: 2.2.2
264
+ rubygems_version: 2.2.3
264
265
  signing_key:
265
266
  specification_version: 4
266
267
  summary: A simple way to manage cloud instances within a multi-subnet network, like