blazing 0.0.16 → 0.1.0.alpha1

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.
Files changed (54) hide show
  1. data/.gitignore +2 -0
  2. data/.rvmrc +1 -1
  3. data/Gemfile +0 -10
  4. data/Gemfile.lock +53 -44
  5. data/Guardfile +8 -0
  6. data/README.md +23 -99
  7. data/Rakefile +21 -4
  8. data/bin/blazing +23 -5
  9. data/blazing.gemspec +19 -8
  10. data/features/help_banner.feature +13 -0
  11. data/features/step_definitions/blazing_steps.rb +1 -0
  12. data/features/support/env.rb +9 -0
  13. data/lib/blazing.rb +4 -13
  14. data/lib/blazing/config.rb +38 -73
  15. data/lib/blazing/dsl_setter.rb +20 -0
  16. data/lib/blazing/recipe.rb +5 -78
  17. data/lib/blazing/runner.rb +44 -2
  18. data/lib/blazing/shell.rb +7 -0
  19. data/lib/blazing/target.rb +44 -134
  20. data/lib/blazing/templates/config.erb +21 -0
  21. data/lib/blazing/templates/hook.erb +43 -0
  22. data/lib/blazing/version.rb +1 -1
  23. data/spec/blazing/config_spec.rb +104 -48
  24. data/spec/blazing/integration/init_spec.rb +8 -37
  25. data/spec/blazing/integration/setup_local_spec.rb +27 -0
  26. data/spec/blazing/integration/setup_remote_spec.rb +32 -0
  27. data/spec/blazing/integration/update_spec.rb +38 -0
  28. data/spec/blazing/recipe_spec.rb +5 -66
  29. data/spec/blazing/runner_spec.rb +41 -6
  30. data/spec/blazing/target_spec.rb +26 -99
  31. data/spec/spec_helper.rb +18 -12
  32. data/spec/support/{config.rb → empty_config.rb} +0 -0
  33. metadata +170 -97
  34. data/TODO +0 -3
  35. data/lib/blazing/base.rb +0 -41
  36. data/lib/blazing/bootstrap.rb +0 -27
  37. data/lib/blazing/cli/base.rb +0 -64
  38. data/lib/blazing/cli/create.rb +0 -32
  39. data/lib/blazing/cli/hook.rb +0 -22
  40. data/lib/blazing/cli/templates/blazing.tt +0 -7
  41. data/lib/blazing/cli/templates/post-hook.tt +0 -25
  42. data/lib/blazing/core_ext/object.rb +0 -8
  43. data/lib/blazing/logger.rb +0 -31
  44. data/lib/blazing/recipes/bundler_recipe.rb +0 -20
  45. data/lib/blazing/recipes/rvm_recipe.rb +0 -11
  46. data/spec/blazing/binary_spec.rb +0 -11
  47. data/spec/blazing/cli/base_spec.rb +0 -94
  48. data/spec/blazing/cli/create_spec.rb +0 -27
  49. data/spec/blazing/cli/hook_spec.rb +0 -16
  50. data/spec/blazing/logger_spec.rb +0 -50
  51. data/spec/blazing/recipes/bundler_recipe_spec.rb +0 -32
  52. data/spec/blazing/recipes/passenger_recipe_spec.rb +0 -6
  53. data/spec/blazing/recipes/rvm_recipe_spec.rb +0 -11
  54. data/spec/blazing/remote_spec.rb +0 -136
@@ -0,0 +1,9 @@
1
+ require 'aruba/cucumber'
2
+ require 'methadone/cucumber'
3
+
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+
6
+ Before do
7
+ # Using "announce" causes massive warnings on 1.9.2
8
+ @puts = true
9
+ end
@@ -1,18 +1,9 @@
1
- require 'thor'
2
- require 'thor/group'
3
- require 'blazing'
4
- require 'blazing/config'
5
- require 'blazing/runner'
6
- require 'blazing/logger'
7
- require 'blazing/target'
8
- require 'blazing/recipe'
9
- require 'blazing/cli/base'
10
- require 'blazing/cli/create'
11
- require 'blazing/cli/hook'
1
+ require "blazing/version"
12
2
 
13
3
  module Blazing
14
4
 
15
- DIRECTORY = 'config'
16
- CONFIGURATION_FILE = 'config/blazing.rb'
5
+ TEMPLATE_ROOT = File.expand_path(File.dirname(__FILE__) + File.join('/', 'blazing', 'templates'))
6
+ DEFAULT_CONFIG_LOCATION = 'config/blazing.rb'
7
+ TMP_HOOK = '/tmp/post-receive'
17
8
 
18
9
  end
@@ -1,90 +1,55 @@
1
- require 'blazing'
2
1
  require 'blazing/target'
2
+ require 'blazing/recipe'
3
+ require 'blazing/dsl_setter'
3
4
 
4
- module Blazing
5
- class Config
5
+ class Blazing::Config
6
6
 
7
- class << self
7
+ extend Blazing::DSLSetter
8
8
 
9
- #
10
- # Read the Configuration File
11
- #
12
- def read(&block)
13
- config = Blazing::Config.new
14
- config.instance_eval(&block)
9
+ attr_reader :file
10
+ attr_accessor :targets
11
+ dsl_setter :repository, :rvm, :rake
15
12
 
16
- config
17
- end
13
+ class << self
18
14
 
19
- #
20
- # Load configuration file and parse it
21
- #
22
- def parse
23
- read do
24
- instance_eval(File.read(Blazing::CONFIGURATION_FILE))
25
- end
26
- end
27
-
28
- #
29
- # DSL Setter helper method
30
- #
31
- def dsl_setter(*names)
32
- names.each do |name|
33
- class_eval <<-EVAL
34
- def #{name}(value = nil)
35
- if value
36
- instance_variable_set("@#{name}", value)
37
- else
38
- instance_variable_get("@#{name}")
39
- end
40
- end
41
- EVAL
42
- end
43
- end
15
+ def parse(configuration_file = nil)
16
+ config = self.new(configuration_file)
17
+ config.instance_eval(File.read(config.file))
44
18
 
19
+ config
45
20
  end
46
21
 
47
- dsl_setter :repository
48
- attr_accessor :targets, :recipes
22
+ end
49
23
 
50
- def initialize
51
- @targets = []
52
- @recipes = []
53
- end
24
+ def initialize(configuration_file = nil)
25
+ @file = configuration_file || Blazing::DEFAULT_CONFIG_LOCATION
26
+ @targets = []
27
+ @recipes = []
28
+ end
54
29
 
55
- def target(name, options = {})
56
- @targets << Blazing::Target.new(name, options.merge(:config => self))
57
- end
30
+ def target(name, location, options = {})
31
+ raise "Name already taken" if targets.find { |t| t.name == name }
32
+ targets << Blazing::Target.new(name, location, self, options)
33
+ end
58
34
 
59
- def use(name, options = {})
60
- @recipes << Blazing::Recipe.new_recipe_by_name(name, options)
35
+ def recipes(recipes = nil)
36
+ if recipes.kind_of? Symbol
37
+ @recipes << Blazing::Recipe.init_by_name(recipes)
38
+ elsif recipes.kind_of? Array
39
+ @recipes = recipes.map { |r| Blazing::Recipe.init_by_name(r) }
40
+ else
41
+ @recipes
61
42
  end
43
+ end
62
44
 
63
- #
64
- # Determines which target is picked, based on defaults and CLI argument
65
- # If only one target is defined, it is the default one
66
- #
67
- def find_target(target_name = nil)
68
- active_target = nil
69
-
70
- if target_name
71
- active_target = targets.find {|target| target.name == target_name }
72
- end
73
-
74
- if active_target.nil? && targets.size == 1
75
- active_target = targets.first
76
- end
77
-
78
- if active_target.nil?
79
- active_target = targets.find {|target| target.default }
80
- end
81
-
82
- if active_target.nil?
83
- raise 'no target specified and no default targets found'
84
- end
85
-
86
- active_target
45
+ def default_target
46
+ if @targets.size > 1
47
+ default = @targets.find { |t| t.options[:default] == true }
48
+ raise 'could not find default target' unless default
49
+ default
50
+ else
51
+ @targets.first
87
52
  end
88
-
89
53
  end
54
+
90
55
  end
@@ -0,0 +1,20 @@
1
+ module Blazing::DSLSetter
2
+
3
+ #
4
+ # DSL Setter helper method
5
+ #
6
+ def dsl_setter(*names)
7
+ names.each do |name|
8
+ class_eval <<-EVAL
9
+ def #{name}(value = nil)
10
+ if value
11
+ instance_variable_set("@#{name}", value)
12
+ else
13
+ instance_variable_get("@#{name}")
14
+ end
15
+ end
16
+ EVAL
17
+ end
18
+ end
19
+
20
+ end
@@ -1,86 +1,13 @@
1
1
  require 'active_support/inflector'
2
- require 'blazing'
3
- # require 'blazing/logger'
4
2
 
5
- module Blazing
6
- class Recipe
3
+ class Blazing::Recipe
7
4
 
5
+ class << self
8
6
 
9
- # TODO: provide hooks for recipe to use bundle exec
10
-
11
- attr_accessor :name, :options
12
-
13
- def initialize(name, options = {})
14
- @name = name.to_s
15
- @options = options
16
- @logger = options[:_logger] ||= Blazing::Logger.new
17
- @runner = Blazing::Runner.new
18
- end
19
-
20
- def recipe_class
21
- # TODO: Unify naming conventions
22
- # Gem Recipe Naming Convention
23
- ('Blazing::' + @name.to_s.gsub('_','/').camelize).constantize
24
- rescue NameError
25
- begin
26
- # Builtin Recipe Naming Convention
27
- ('Blazing::' + (@name.to_s + '_recipe').camelize).constantize
28
- rescue NameError
29
- @logger.log :error, "unable to load #{@name} recipe"
30
- return nil
31
- end
7
+ def init_by_name(name)
8
+ "Blazing::Recipe::#{name.to_s.camelize}".constantize.new
32
9
  end
33
10
 
34
- def run
35
- raise 'run method must be implemented in recipe'
36
- end
37
-
38
- class << self
39
-
40
- def new_recipe_by_name(name, options = {})
41
- load_builtin_recipes
42
- load_gem_recipes
43
- new(name, options).recipe_class.new(name, options)
44
- end
45
-
46
- def load_builtin_recipes
47
- dir = File.join(File.dirname(__FILE__), "/recipes")
48
- $LOAD_PATH.unshift(dir)
49
- Dir[File.join(dir, "*.rb")].each { |file| load File.basename(file) }
50
- end
51
-
52
- def load_gem_recipes
53
- # TODO: I'm sure there is a better way to do this...
54
- gems = open('Gemfile').grep(/blazing-/).map { |l| l.match(/(blazing-.*)\'\,/)[1] }
55
- gems.each do |gem|
56
- gem_lib_path = $:.find { |p| p.include? gem }
57
- recipes_path = File.join(gem_lib_path, gem, 'recipes')
58
- recipes = Dir.entries(recipes_path).delete_if { |r| r == '.' || r == '..' }
59
- recipes.each { |recipe| require File.join(gem, 'recipes', recipe) }
60
- end
61
- end
62
-
63
- def load_local_recipes
64
- #TODO: Implement
65
- end
66
-
67
- #
68
- # Return the list of available recipes based
69
- # on class hierarchy
70
- #
71
- def list
72
- descendants = []
73
-
74
- load_builtin_recipes
75
- load_gem_recipes
76
-
77
- ObjectSpace.each_object(Class) do |k|
78
- descendants.unshift k if k < self
79
- end
80
- descendants.uniq!
81
- descendants
82
- end
83
-
84
- end
85
11
  end
12
+
86
13
  end
@@ -1,7 +1,49 @@
1
+ require 'erb'
2
+ require 'methadone'
3
+
1
4
  class Blazing::Runner
2
5
 
3
- def run(command)
4
- system command
6
+ include Methadone::CLILogging
7
+
8
+ def initialize(config = nil, target = nil)
9
+ if config
10
+ @config = config
11
+ @target = @config.targets.find { |t| t.name == target.to_s } || @config.default_target
12
+ end
13
+ end
14
+
15
+ def exec(command)
16
+ command_method = "#{command.gsub(':', '_')}_command"
17
+ raise "Unknown Command: #{command}" unless self.respond_to? command_method
18
+ self.send command_method
19
+ end
20
+
21
+ def init_command
22
+ info("Creating an example config file in #{Blazing::DEFAULT_CONFIG_LOCATION}")
23
+ info("Customize it to your needs")
24
+
25
+ Dir.mkdir 'config' unless Dir.exists? 'config'
26
+ configuration_file = ERB.new(File.read("#{Blazing::TEMPLATE_ROOT}/config.erb")).result
27
+
28
+ File.open(Blazing::DEFAULT_CONFIG_LOCATION,"wb") do |f|
29
+ f.puts configuration_file
30
+ end
31
+ end
32
+
33
+ def setup_local_command
34
+ repository = Grit::Repo.new(Dir.pwd)
35
+ @config.targets.each do |target|
36
+ info("Adding new remote #{target.name} pointing to #{target.location}")
37
+ repository.config["remote.#{target.name}.url"] = target.location
38
+ end
39
+ end
40
+
41
+ def setup_remote_command
42
+ @config.default_target.setup
43
+ end
44
+
45
+ def update_command
46
+ @config.default_target.update
5
47
  end
6
48
 
7
49
  end
@@ -0,0 +1,7 @@
1
+ class Blazing::Shell
2
+
3
+ def run(command)
4
+ system command
5
+ end
6
+
7
+ end
@@ -1,151 +1,61 @@
1
- require 'blazing'
2
- require 'blazing/core_ext/object'
3
- require 'blazing/config'
4
- require 'blazing/bootstrap'
1
+ require 'blazing/shell'
5
2
 
6
- module Blazing
7
- class Target
3
+ class Blazing::Target
8
4
 
9
- include Blazing::Target::Bootstrap
5
+ attr_accessor :name, :location, :options
10
6
 
11
- attr_accessor :name, :recipes
12
-
13
- AVAILABLE_SETTINGS = [:deploy_to, :host, :user, :path, :default, :branch]
14
-
15
- class << self
16
-
17
- def bootstrap(name)
18
- target = config.find_target(name)
19
- runner = Blazing::Runner.new
20
- # TODO: Use a Wrapper to Net::SSH
21
- target.clone_repository
22
- target.setup_post_receive_hook
23
- setup target.name
24
- end
25
-
26
- def deploy(name)
27
- target = config.find_target(name)
28
- runner = Blazing::Runner.new
29
- deploy_command = "git push #{name}"
30
- deploy_command += " #{target.branch}:#{target.branch}" if target.branch
31
-
32
- # TODO: checkout branch if we pushed to a branch which is not checked out
33
- runner.run deploy_command
34
- end
35
-
36
- def setup(name)
37
- if name
38
- config.find_target(name).add_target_as_remote
39
- else
40
- config.targets.each do |target|
41
- target.add_target_as_remote
42
- end
43
- end
44
- end
45
-
46
- def post_receive(name)
47
- target = config.find_target(name)
48
- target.set_git_dir
49
- target.reset_head!
50
- @recipes.delete_if { |recipe| recipe.name == 'rvm' }
51
- target.run_recipes
52
- end
53
-
54
- def config
55
- Blazing::Config.parse
56
- end
57
-
58
- def runner
59
- Blazing::Runner.new
60
- end
61
-
62
- end
63
-
64
- def initialize(name, options = {})
65
- @name = name.to_s
66
- @logger = options[:_logger] ||= Blazing::Logger.new
67
- @runner = options[:_runner] ||= Blazing::Runner.new
68
- @hook = options[:_hook] ||= Blazing::CLI::Hook
69
-
70
- @config = options[:config] || Blazing::Config.parse
71
-
72
- @repository = @config.repository
73
- create_accessors_from_config(options)
74
- load_recipes
75
- end
76
-
77
- def create_accessors_from_config(options)
78
- assign_settings(options)
79
- parse_deploy_to_string unless @deploy_to.blank?
80
- ensure_mandatory_settings
81
- end
7
+ def initialize(name, location, config, options = {})
8
+ @name = name
9
+ @location = location
10
+ @config = config
11
+ @options = options
12
+ @shell = Blazing::Shell.new
13
+ end
82
14
 
83
- def assign_settings(options)
84
- AVAILABLE_SETTINGS.each do |option|
85
- instance_variable_set("@#{option}", options[option])
86
- self.class.send(:attr_accessor, option)
87
- end
88
- end
15
+ def setup
16
+ @shell.run "ssh #{user}@#{host} '#{clone_repository} && #{setup_repository}'"
17
+ self.update
18
+ end
89
19
 
90
- # If the :deploy_to option is set, user, host and path are overriden
91
- def parse_deploy_to_string
92
- @host = @deploy_to.scan(/@(.*):/).join
93
- @user = @deploy_to.scan(/(.*)@/).join
94
- @path = @deploy_to.scan(/:(.*)/).join
95
- end
20
+ def update
21
+ hook = ERB.new(File.read("#{Blazing::TEMPLATE_ROOT}/hook.erb")).result(binding)
96
22
 
97
- # Raise an error if one of the required options is still empty
98
- def ensure_mandatory_settings
99
- [:host, :user, :path].each do |option|
100
- raise "#{option} can't be blank!" if instance_variable_get("@#{option}").blank?
101
- end
23
+ File.open(Blazing::TMP_HOOK, "wb") do |f|
24
+ f.puts hook
102
25
  end
103
26
 
104
- def set_git_dir
105
- ENV['GIT_DIR'] = '.git'
106
- end
27
+ copy_hook
28
+ @shell.run "ssh #{user}@#{host} #{make_hook_executable}"
29
+ end
107
30
 
108
- def reset_head!
109
- @runner ||= Blazing::Runner.new
110
- @runner.run 'git reset --hard HEAD'
111
- end
31
+ def path
32
+ @location.match(/:(.*)$/)[1]
33
+ end
112
34
 
113
- #
114
- # Called by post-receive hook to determine rvm usage
115
- #
116
- def use_rvm?
117
- @rvm_recipe = @recipes.find { |recipe| recipe.name == 'rvm' }
118
- @recipes.delete_if { |recipe| recipe.name == 'rvm' }
119
- if @rvm_recipe
120
- @rvm_recipe.options[:rvm_string]
121
- else
122
- 'none'
123
- end
124
- end
35
+ def host
36
+ host = @location.match(/@(.*):/)
37
+ host[1] unless host.nil?
38
+ end
125
39
 
126
- def load_recipes
40
+ def user
41
+ user = @location.match(/(.*)@/)
42
+ user[1] unless user.nil?
43
+ end
127
44
 
128
- # TODO: For now, recipes can be assigned only in the global
129
- # namespace of the config. Make it possible for targets to
130
- # define recipes individually
45
+ def clone_repository
46
+ "git clone #{@config.repository} #{path}"
47
+ end
131
48
 
132
- @recipes = @config.recipes if @recipes.blank?
133
- Blazing::Recipe.load_builtin_recipes
134
- end
49
+ def copy_hook
50
+ @shell.run "scp #{Blazing::TMP_HOOK} #{user}@#{host}:#{path}/.git/hooks/post-receive"
51
+ end
135
52
 
136
- def run_recipes
137
- run_bootstrap_recipes
138
- @recipes.each do |recipe|
139
- recipe.run
140
- end
141
- end
53
+ def make_hook_executable
54
+ "chmod +x #{path}/.git/hooks/post-receive"
55
+ end
142
56
 
143
- def run_bootstrap_recipes
144
- bundler = @recipes.find { |r| r.name == 'bundler' }
145
- if bundler
146
- bundler.run
147
- @recipes.delete_if { |r| r.name == 'bundler' }
148
- end
149
- end
57
+ def setup_repository
58
+ "cd #{path} && git config receive.denyCurrentBranch ignore"
150
59
  end
60
+
151
61
  end