divergence 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -17,3 +17,5 @@ test/version_tmp
17
17
  tmp
18
18
  log/*.log
19
19
  .DS_Store
20
+ test/app_root
21
+ test/cache_root
data/README.md CHANGED
@@ -24,14 +24,48 @@ All configuration happens in `config/config.rb`. You must set the git repository
24
24
 
25
25
  You will probably want divergence to take over port 80 on your testing server, so you may have to update the forwarding host/port. Note, this is the address where your actual web application can be reached.
26
26
 
27
+ A sample config could look like this:
28
+
29
+ ``` ruby
30
+ Divergence::Application.configure do |config|
31
+ config.git_path = "/path/to/git_root"
32
+ config.app_path = "/path/to/app_root"
33
+ config.cache_path = "/path/to/cache_root"
34
+
35
+ config.forward_host = 'localhost'
36
+ config.forward_port = 80
37
+
38
+ config.callbacks :after_swap do
39
+ restart_passenger
40
+ end
41
+
42
+ config.callbacks :after_cache, :after_webhook do
43
+ bundle_install :path => "vendor/bundle"
44
+ end
45
+
46
+ config.callbacks :on_branch_discover do |subdomain|
47
+ case subdomain
48
+ when "release-1"
49
+ "test_branch"
50
+ when "release-2"
51
+ "other_branch"
52
+ end
53
+ end
54
+ end
55
+ ```
56
+
27
57
  ### Callbacks
28
58
 
29
59
  Divergence lets you hook into various callbacks throughout the entire process. These are defined in `config/callbacks.rb`. Most callbacks automatically change the current working directory for you in order to make modifications as simple as possible.
30
60
 
31
61
  The available callbacks are:
32
62
 
33
- * before_swap
63
+ * before_cache
34
64
  * Active dir: git repository
65
+ * after_cache
66
+ * Active dir: cached folder path
67
+ * before_swap
68
+ * Active dir: cached folder path
35
69
  * after_swap
36
70
  * Active dir: application
37
71
  * before_pull
@@ -47,11 +81,22 @@ The available callbacks are:
47
81
  * Active dir: git repository
48
82
  * Executes if the subdomain has a dash in the name. The subdomain name is passed to the callback in the options hash.
49
83
  * If the callback returns nil, Divergence will try to auto-detect the branch name, otherwise it will use whatever you return.
84
+ * before_webook
85
+ * Active dir: git repository
86
+ * Runs before a branch is updated via webhooks.
87
+ * after_webhook
88
+ * Active dir: cached folder path
89
+ * Runs after a webhook update completes
50
90
 
51
91
  There are also some built-in helper methods that are available inside callbacks. They are:
52
92
 
53
93
  * bundle_install
94
+ * Recommended - after_cache, after_webhook
95
+ * Options:
96
+ * :deployment => boolean
97
+ * :path => string
54
98
  * restart_passenger
99
+ * Recommended - after_swap
55
100
 
56
101
  ### Github Service Hook
57
102
 
@@ -91,8 +136,9 @@ Divergence currently does not support HTTPS on its own; however, you can still u
91
136
 
92
137
  ## TODO
93
138
 
94
- * Handle multiple users at the same time
95
- * Build-in HTTPS support
139
+ * Handle simultaneous users better
140
+ * Built-in HTTPS support
141
+ * Helpers for more frameworks
96
142
 
97
143
  ## Contributing
98
144
 
@@ -16,6 +16,7 @@ module CLI
16
16
  def create_directories
17
17
  empty_directory "config"
18
18
  empty_directory "log"
19
+ empty_directory "tmp"
19
20
  end
20
21
 
21
22
  def copy_templates
@@ -36,8 +37,19 @@ module CLI
36
37
  cmd = 'rackup'
37
38
  cmd << " -p #{options[:port]}" if options[:port]
38
39
  cmd << " -D" unless options[:dev]
40
+ cmd << " -P tmp/rack.pid"
39
41
 
40
42
  exec cmd
43
+
44
+ unless options[:dev]
45
+ puts "Divergence is now running"
46
+ end
47
+ end
48
+
49
+ desc "stop", "Stop divergence"
50
+ def stop
51
+ `kill -9 $(cat tmp/rack.pid) && rm tmp/rack.pid`
52
+ puts "Divergence halted"
41
53
  end
42
54
  end
43
55
  end
@@ -20,7 +20,6 @@ Gem::Specification.new do |gem|
20
20
  gem.add_dependency "rack"
21
21
  gem.add_dependency "rack-proxy"
22
22
  gem.add_dependency "thor"
23
- gem.add_dependency "git"
24
23
  gem.add_dependency "json"
25
24
  gem.add_development_dependency "rack-test"
26
25
  end
@@ -1,8 +1,15 @@
1
1
  require File.expand_path('../callbacks', __FILE__)
2
2
 
3
3
  Divergence::Application.configure do |config|
4
- config.git_path = nil # Change this to the git repository path
5
- config.app_path = nil # and this to your application's path.
4
+ config.git_path = nil # Change this to the git repository path
5
+ config.app_path = nil # and this to your application's path.
6
+ config.cache_path = nil # This should be an empty directory
7
+
8
+ # The number of branches to cache for quick switching. If you're
9
+ # switching around between many branches frequently, you might
10
+ # want to raise this. Keep in mind that each cached branch will
11
+ # have it's own Passenger instance, so don't get too carried away.
12
+ # config.cache_num = 5
6
13
 
7
14
  # Where should we proxy this request to? Normally you can leave
8
15
  # the host as 'localhost', but if you are using virtual hosts in
@@ -1,12 +1,14 @@
1
1
  require "rack/proxy"
2
- require "git"
3
2
  require "json"
4
3
  require "logger"
4
+ require "fileutils"
5
5
 
6
6
  require "rack_ssl_hack"
7
7
  require "divergence/version"
8
8
  require "divergence/config"
9
+ require "divergence/application"
9
10
  require "divergence/git_manager"
11
+ require "divergence/cache_manager"
10
12
  require "divergence/helpers"
11
13
  require "divergence/request_parser"
12
14
  require "divergence/respond"
@@ -30,25 +32,15 @@ module Divergence
30
32
  end
31
33
 
32
34
  def initialize
33
- file_checks
35
+ config.ok?
34
36
 
35
- @g = GitManager.new(config)
37
+ @git = GitManager.new(config.git_path)
38
+ @cache = CacheManager.new(config.cache_path, config.cache_num)
39
+ @active_branch = ""
36
40
  end
37
41
 
38
42
  def config
39
43
  @@config
40
44
  end
41
-
42
- private
43
-
44
- def file_checks
45
- unless File.exists?(config.app_path)
46
- raise "Configured path not found: #{config.app_path}"
47
- end
48
-
49
- unless File.exists?(config.git_path)
50
- raise "Configured git path not found: #{config.git_path}"
51
- end
52
- end
53
45
  end
54
46
  end
@@ -0,0 +1,27 @@
1
+ module Divergence
2
+ # Responsible for managing the cache folders and swapping
3
+ # the codebases around.
4
+ class Application < Rack::Proxy
5
+ # Prepares the filesystem for loading up a branch
6
+ def prepare(branch, opts = {})
7
+ return nil if branch == @active_branch
8
+
9
+ unless @cache.is_cached?(branch)
10
+ @cache.add branch, @git.switch(branch)
11
+ end
12
+
13
+ @cache.path(branch)
14
+ end
15
+
16
+ # Links the application directory to the given path,
17
+ # which is always a cache directory in our case.
18
+ def link!(path)
19
+ Application.log.info "Link: #{path} -> #{config.app_path}"
20
+
21
+ config.callback :before_swap, path
22
+ FileUtils.rm config.app_path if File.exists?(config.app_path)
23
+ FileUtils.ln_s path, config.app_path, :force => true
24
+ config.callback :after_swap, config.app_path
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module Divergence
2
+ class CacheManager
3
+ def initialize(cache_path, cache_num)
4
+ @cache_path = cache_path
5
+ @cache_num = cache_num
6
+
7
+ Dir.chdir @cache_path do
8
+ @cached_branches = Dir['*/'].map {|dir| dir.gsub('/', '')}
9
+ end
10
+ end
11
+
12
+ def is_cached?(branch)
13
+ @cached_branches.include?(branch)
14
+ end
15
+
16
+ def add(branch, src_path)
17
+ Application.log.info "Caching: #{branch} from #{src_path}"
18
+
19
+ prune_cache!
20
+
21
+ Application.config.callback :before_cache, src_path, :branch => branch
22
+
23
+ FileUtils.mkdir_p path(branch)
24
+ sync branch, src_path
25
+ @cached_branches.push branch
26
+
27
+ Application.config.callback :after_cache, path(branch), :branch => branch
28
+ end
29
+
30
+ def sync(branch, src_path)
31
+ `rsync -a --delete #{src_path}/* #{path(branch)}`
32
+ end
33
+
34
+ def path(branch)
35
+ "#{@cache_path}/#{branch}"
36
+ end
37
+
38
+ private
39
+
40
+ # Delete the oldest cached branches to make room for new
41
+ def prune_cache!
42
+ Dir.chdir @cache_path do
43
+ branches = Dir.glob('*/')
44
+ return if branches.nil? or branches.length <= @cache_num
45
+
46
+ branches
47
+ .sort_by {|f| File.mtime(f)}[@cache_num..-1]
48
+ .each do|dir|
49
+ FileUtils.rm_rf(dir)
50
+ @cached_branches.delete(dir.gsub('/', ''))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -2,12 +2,17 @@ module Divergence
2
2
  class Configuration
3
3
  include Enumerable
4
4
 
5
- attr_accessor :app_path, :git_path
5
+ attr_accessor :app_path, :git_path, :cache_path
6
+ attr_accessor :cache_num
6
7
  attr_accessor :forward_host, :forward_port
7
8
 
8
9
  def initialize
9
10
  @git_path = nil
10
11
  @app_path = nil
12
+ @cache_path = nil
13
+
14
+ @cache_num = 5
15
+
11
16
  @forward_host = 'localhost'
12
17
  @forward_port = 80
13
18
 
@@ -15,33 +20,46 @@ module Divergence
15
20
  @helpers = Divergence::Helpers.new(self)
16
21
  end
17
22
 
18
- # Might get rid of realpath in the future because it
19
- # resolves symlinks and that could be problematic
20
- # with capistrano in case someone accidentally deploys.
21
- def app_path=(p)
22
- @app_path = File.realpath(p)
23
- end
23
+ def ok?
24
+ [:git_path, :app_path, :cache_path].each do |path|
25
+ if instance_variable_get("@#{path}").nil?
26
+ raise "Configure #{path} before running"
27
+ end
28
+ end
29
+
30
+ unless File.exists?(@git_path)
31
+ raise "Configured git path not found: #{@git_path}"
32
+ end
24
33
 
25
- def git_path=(p)
26
- @git_path = File.realpath(p)
34
+ unless File.exists?(@cache_path)
35
+ FileUtils.mkdir_p @cache_path
36
+ end
27
37
  end
28
38
 
29
39
  # Lets a user define a callback for a specific event
30
- def callbacks(name, &block)
31
- unless @callback_store.has_key?(name)
32
- @callback_store[name] = []
33
- end
40
+ def callbacks(*names, &block)
41
+ names.each do |name|
42
+ unless @callback_store.has_key?(name)
43
+ @callback_store[name] = []
44
+ end
34
45
 
35
- @callback_store[name].push block
46
+ @callback_store[name].push block
47
+ end
36
48
  end
37
49
 
38
- def callback(name, args = {})
50
+ def callback(name, run_path=nil, args = {})
39
51
  return unless @callback_store.has_key?(name)
40
52
 
41
- Application.log.debug "Execute callback: #{name.to_s}"
53
+ if run_path.nil? or !File.exists?(run_path)
54
+ run_path = Dir.pwd
55
+ end
56
+
57
+ Application.log.debug "Execute callback: #{name.to_s} in #{run_path}"
42
58
 
43
- @callback_store[name].each do |cb|
44
- @helpers.execute cb, args
59
+ Dir.chdir run_path do
60
+ @callback_store[name].each do |cb|
61
+ @helpers.execute cb, args
62
+ end
45
63
  end
46
64
  end
47
65
 
@@ -1,81 +1,47 @@
1
1
  module Divergence
2
+ # Manages the configured Git repository
2
3
  class GitManager
3
4
  attr_reader :current_branch
4
5
 
5
- def initialize(config)
6
- @config = config
7
- @app_path = config.app_path
8
- @git_path = config.git_path
9
-
6
+ def initialize(git_path)
7
+ @git_path = git_path
10
8
  @log = Logger.new('./log/git.log')
11
- @git = Git.open(@git_path, :log => @log)
12
-
13
- @current_branch = @git.branch
14
- @new_branch = false
9
+ @current_branch = current_branch
15
10
  end
16
11
 
17
- def prepare_directory(branch, force=false)
18
- return if is_current?(branch) and !force
12
+ def switch(branch, force=false)
13
+ return @git_path if is_current?(branch) and !force
14
+
19
15
  pull branch
20
- end
21
-
22
- # Performs the swap between the git directory and the working
23
- # app directory. We want to copy the files without copying
24
- # the .git directory, but this is a temporary dumb solution.
25
- #
26
- # Future idea: try the capistrano route and simply symlink
27
- # to the git directory instead of copying files.
28
- #
29
- # TODO: make this more ruby-like.
30
- def swap!
31
- return unless @new_branch
32
-
33
- Dir.chdir @config.git_path do
34
- @config.callback :before_swap
35
- end
36
-
37
- Application.log.info "Swap: #{@git_path} -> #{@app_path}"
38
- `rsync -a --delete --exclude=.git #{@git_path}/* #{@app_path}`
39
- @new_branch = false
40
-
41
- Dir.chdir @config.app_path do
42
- @config.callback :after_swap
43
- end
16
+ return @git_path
44
17
  end
45
18
 
46
19
  # Since underscores are technically not allowed in URLs,
47
20
  # but they are allowed in Git branch names, we have to do
48
21
  # some magic to possibly convert dashes to underscores
49
22
  # so we can load the right branch.
50
- #
51
- # Another possible thing to explore is converting all
52
- # dashes in the URL to a regex search against all branches
53
- # in this repository to avoid the current brute-force
54
- # solution we're using.
55
23
  def discover(branch)
56
24
  return branch if is_branch?(branch)
57
25
 
58
- Dir.chdir @git_path do
59
- resp = @config.callback :on_branch_discover, branch
26
+ resp = Application.config.callback :on_branch_discover, @git_path, branch
60
27
 
61
- unless resp.nil?
62
- return resp
63
- end
64
-
65
- local_search = "^" + branch.gsub(/-/, ".") + "$"
66
- remote_search = "^remotes/origin/(" + branch.gsub(/-/, ".") + ")$"
67
- local_r = Regexp.new(local_search, Regexp::IGNORECASE)
68
- remote_r = Regexp.new(remote_search, Regexp::IGNORECASE)
69
-
70
- `git branch -a`.split("\n").each do |b|
71
- b = b.gsub('*', '').strip
72
-
73
- return b if local_r.match(b)
74
- if remote_r.match(b)
75
- return remote_r.match(b)[1]
76
- end
77
- end
28
+ unless resp.nil?
29
+ return resp
78
30
  end
31
+
32
+ local_search = "^" + branch.gsub(/-/, ".") + "$"
33
+ remote_search = "^remotes/origin/(" + branch.gsub(/-/, ".") + ")$"
34
+ local_r = Regexp.new(local_search, Regexp::IGNORECASE)
35
+ remote_r = Regexp.new(remote_search, Regexp::IGNORECASE)
36
+
37
+ git('branch -a').split("\n").each do |b|
38
+ b = b.gsub('*', '').strip
39
+
40
+ return b if local_r.match(b)
41
+ if remote_r.match(b)
42
+ return remote_r.match(b)[1]
43
+ end
44
+ end
79
45
 
80
46
  raise "Unable to automatically detect branch. Given = #{branch}"
81
47
  end
@@ -86,6 +52,14 @@ module Divergence
86
52
 
87
53
  private
88
54
 
55
+ def current_branch
56
+ git('branch -a').split("\n").each do |b|
57
+ if b[0, 2] == '* '
58
+ return b.gsub('* ', '').strip
59
+ end
60
+ end
61
+ end
62
+
89
63
  def is_branch?(branch)
90
64
  Dir.chdir @git_path do
91
65
  # This is fast, but only works on locally checked out branches
@@ -100,26 +74,11 @@ module Divergence
100
74
 
101
75
  def pull(branch)
102
76
  if checkout(branch)
103
- Dir.chdir @config.git_path do
104
- @config.callback :before_pull
105
- end
106
-
107
- #@git.pull 'origin', branch
108
- @git.chdir do
109
- # For some reason, I'm having issues with the pull
110
- # that's built into the library. Doing this manually
111
- # for now.
112
- @log.info "git pull origin #{branch} 2>&1"
113
- `git pull origin #{branch} 2>&1`
114
- end
115
-
116
- Dir.chdir @config.git_path do
117
- @config.callback :after_pull
118
- end
77
+ Application.config.callback :before_pull, @git_path
78
+ git "pull origin #{branch}"
79
+ Application.config.callback :after_pull, @git_path
119
80
  else
120
- Dir.chdir @config.git_path do
121
- @config.callback :on_pull_error
122
- end
81
+ Application.config.callback :on_pull_error, @git_path
123
82
 
124
83
  return false
125
84
  end
@@ -130,21 +89,34 @@ module Divergence
130
89
  reset
131
90
 
132
91
  begin
133
- @git.checkout branch, :force => true
92
+ git "checkout -f #{branch}"
134
93
  @current_branch = branch
135
- @new_branch = true
136
94
  rescue
137
95
  return false
138
96
  end
139
97
  end
140
98
 
141
99
  def reset
142
- @git.reset_hard('HEAD')
100
+ git 'reset --hard'
143
101
  end
144
102
 
145
103
  # Fetch all remote branch information
146
104
  def fetch
147
- @git.fetch
105
+ git :fetch
106
+ end
107
+
108
+ def git(cmd)
109
+ Dir.chdir @git_path do
110
+ @log.info "git #{cmd.to_s}"
111
+ out = `git #{cmd.to_s} 2>&1`
112
+
113
+ if $?.exitstatus != 0
114
+ Application.log.error "git #{cmd.to_s} failed"
115
+ Application.log.error out
116
+ end
117
+
118
+ return out
119
+ end
148
120
  end
149
121
  end
150
122
  end
@@ -1,5 +1,3 @@
1
- require 'fileutils'
2
-
3
1
  module Divergence
4
2
  class Helpers
5
3
  def initialize(config)
@@ -12,22 +10,32 @@ module Divergence
12
10
 
13
11
  private
14
12
 
15
- def bundle_install
13
+ def bundle_install(opts={})
16
14
  Application.log.debug "bundle install"
17
-
18
- Dir.chdir @config.app_path do
19
- `bundle install`
15
+
16
+ begin
17
+ cmd = 'bundle install'
18
+ cmd << ' --deployment' if opts[:deployment]
19
+ cmd << " --path #{opts[:path]}" if opts[:path]
20
+ cmd << ' --without development test'
21
+ result = `#{cmd}`
22
+ Application.log.debug result
23
+ rescue
24
+ Application.log.error "bundle install failed!"
25
+ Application.log.error e.message
20
26
  end
21
27
  end
22
28
 
23
29
  def restart_passenger
24
30
  Application.log.debug "Restarting passenger..."
25
31
 
26
- Dir.chdir @config.app_path do
27
- begin
28
- FileUtils.touch 'tmp/restart.txt'
29
- rescue
32
+ begin
33
+ unless File.exists? 'tmp'
34
+ FileUtils.mkdir_p 'tmp'
30
35
  end
36
+
37
+ FileUtils.touch 'tmp/restart.txt'
38
+ rescue
31
39
  end
32
40
  end
33
41
  end
@@ -1,8 +1,7 @@
1
1
  module Divergence
2
2
  class RequestParser
3
- def initialize(env, git)
3
+ def initialize(env)
4
4
  @req = Rack::Request.new(env)
5
- @git = git
6
5
  end
7
6
 
8
7
  def raw
@@ -1,9 +1,9 @@
1
1
  module Divergence
2
2
  class Application < Rack::Proxy
3
- # The main entry point for the application. This is caled
3
+ # The main entry point for the application. This is called
4
4
  # by Rack.
5
5
  def call(env)
6
- @req = RequestParser.new(env, @g)
6
+ @req = RequestParser.new(env)
7
7
 
8
8
  # First, lets find out what subdomain/git branch
9
9
  # we're dealing with (if any).
@@ -15,18 +15,27 @@ module Divergence
15
15
  # Handle webhooks from Github for updating the current
16
16
  # branch if necessary.
17
17
  if @req.is_webhook?
18
- return Webhook.handle @g, @req
18
+ return handle_webhook
19
19
  end
20
20
 
21
- # Ask our GitManager to prepare the directory
22
- # for the given branch.
23
- result = @g.prepare_directory @req.branch
24
- if result === false
25
- return error!
26
- end
21
+ # Lets get down to business.
22
+ begin
23
+ # Get the proper branch name using a touch of magic
24
+ branch = @git.discover(@req.subdomain)
27
25
 
28
- # And then perform the codebase swap
29
- @g.swap!
26
+ # Prepare the branch and cache if needed
27
+ path = prepare(branch)
28
+
29
+ # If we're requesting a different branch than the
30
+ # one currently loaded, we'll need to link it to
31
+ # the application directory.
32
+ link!(path) unless path.nil?
33
+
34
+ @active_branch = branch
35
+ rescue Exception => e
36
+ Application.log.error e.message
37
+ return error!(branch)
38
+ end
30
39
 
31
40
  # We're finished, pass the request through.
32
41
  proxy(env)
@@ -56,8 +65,8 @@ module Divergence
56
65
  env["HTTP_HOST"] = "#{config.forward_host}:#{config.forward_port}"
57
66
  end
58
67
 
59
- def error!
60
- Application.log.error "Branch #{@req.branch} does not exist"
68
+ def error!(branch)
69
+ Application.log.error "Branch #{branch} does not exist"
61
70
  Application.log.error @req.raw
62
71
 
63
72
  public_path = File.expand_path('../../../public', __FILE__)
@@ -1,3 +1,3 @@
1
1
  module Divergence
2
- VERSION = "0.0.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,30 +1,34 @@
1
1
  module Divergence
2
- class Webhook
3
- def self.handle(git, req)
4
- hook = JSON.parse(req['payload'])
2
+ class Application
3
+ def handle_webhook
4
+ hook = JSON.parse(@req['payload'])
5
5
  branch = hook["ref"].split("/").last.strip
6
6
 
7
7
  Application.log.info "Webhook: received for #{branch} branch"
8
8
 
9
9
  # If the webhook is for the currently active branch,
10
10
  # then we perform a pull and a swap.
11
- if git.is_current?(branch)
11
+ if @cache.is_cached?(branch)
12
12
  Application.log.info "Webhook: updating #{branch}"
13
13
 
14
- git.prepare_directory(branch, true)
15
- git.swap!
16
-
14
+ git_path = @git.switch branch, :force => true
15
+
16
+ config.callback :before_webhook, git_path, :branch => branch
17
+ @cache.sync branch, git_path
18
+ config.callback :after_webhook, @cache.path(branch), :branch => branch
19
+
17
20
  ok
18
21
  else
22
+ Application.log.info "Webhook: ignoring #{branch}"
19
23
  ignore
20
24
  end
21
25
  end
22
26
 
23
- def self.ok
27
+ def ok
24
28
  [200, {"Content-Type" => "text/html"}, ["OK"]]
25
29
  end
26
30
 
27
- def self.ignore
31
+ def ignore
28
32
  [200, {"Content-Type" => "text/html"}, ["IGNORE"]]
29
33
  end
30
34
  end
@@ -1,10 +1,12 @@
1
1
  Divergence::Application.configure do |config|
2
- config.git_path = "test/git_root"
3
- config.app_path = "test/app_root"
2
+ config.git_path = "./test/git_root"
3
+ config.app_path = "./test/app_root"
4
+ config.cache_path = "./test/cache_root"
5
+
4
6
  config.forward_host = 'localhost'
5
7
  config.forward_port = 80
6
8
 
7
- config.callbacks :after_swap do
9
+ config.callbacks :after_swap, :after_webhook do
8
10
  # Run anything after the swap finishes
9
11
  end
10
12
  end
@@ -4,15 +4,19 @@ class ConfigureTest < Test::Unit::TestCase
4
4
  def test_config
5
5
  git_path = File.expand_path('../git_root', __FILE__)
6
6
  app_path = File.expand_path('../app_root', __FILE__)
7
+ cache_path = File.expand_path('../cache_root', __FILE__)
7
8
 
8
9
  Divergence::Application.configure do |config|
9
10
  config.git_path = git_path
10
11
  config.app_path = app_path
12
+ config.cache_path = cache_path
13
+
11
14
  config.forward_host = 'localhost'
12
15
  config.forward_port = 80
13
16
  end
14
17
 
15
18
  assert app.config.app_path, app_path
16
19
  assert app.config.git_path, git_path
20
+ assert app.config.cache_path, cache_path
17
21
  end
18
22
  end
@@ -2,38 +2,30 @@ require 'test_helper'
2
2
 
3
3
  class GitTest < Test::Unit::TestCase
4
4
  def test_ignore
5
- force_branch :master
6
5
  mock_get 'master.example.com'
7
6
 
8
- git = Git.open('test/git_root')
9
- assert_equal "master", git.current_branch
7
+ assert_equal "master", active_branch
10
8
 
11
9
  # and again...
12
10
  mock_get 'master.example.com'
13
- assert_equal 'master', git.current_branch
11
+ assert_equal 'master', active_branch
14
12
  end
15
13
 
16
14
  def test_switch_branch
17
- force_branch :master
18
15
  mock_get 'branch1.example.com'
19
-
20
- git = Git.open('test/git_root')
21
- assert_equal 'branch1', git.current_branch
16
+ assert_equal 'branch1', active_branch
22
17
  end
23
18
 
24
19
  def test_branch_discover
25
- force_branch :master
26
20
  mock_get 'branch-1.example.com'
27
-
28
- git = Git.open('test/git_root')
29
- assert_equal 'branch_1', git.current_branch
21
+ assert_equal 'branch_1', active_branch
30
22
 
31
23
  mock_get 'branch-with-complex-name-1.example.com'
32
- assert_equal 'branch_with_complex_name-1', git.current_branch
24
+ assert_equal 'branch_with_complex_name-1', active_branch
33
25
  end
34
26
 
35
27
  def test_dirty_switch
36
- force_branch :master
28
+ mock_get "master.example.com"
37
29
 
38
30
  File.open 'test/git_root/test.txt', 'a' do |f|
39
31
  f.write 'modifying this'
@@ -41,19 +33,14 @@ class GitTest < Test::Unit::TestCase
41
33
 
42
34
  mock_get 'branch1.example.com'
43
35
 
44
- git = Git.open('test/git_root')
45
- assert_equal 'branch1', git.current_branch
36
+ assert_equal 'branch1', active_branch
46
37
  end
47
38
 
48
39
  def test_swap
49
- force_branch :master
50
40
  mock_get "branch1.example.com"
51
41
 
52
42
  assert File.exists? 'test/app_root/test.txt'
53
- file = File.open 'test/app_root/test.txt'
54
- contents = file.read.strip
55
- file.close
56
43
 
57
- assert_equal "branch1", contents
44
+ assert_equal "branch1", active_branch
58
45
  end
59
46
  end
@@ -3,6 +3,9 @@ require "rack"
3
3
  require "rack/test"
4
4
 
5
5
  require "./lib/divergence"
6
+ require "./test/config"
7
+
8
+ #require 'debugger'; debugger
6
9
 
7
10
  Test::Unit::TestCase.class_eval do
8
11
  include Rack::Test::Methods
@@ -17,10 +20,11 @@ class Test::Unit::TestCase
17
20
  @d
18
21
  end
19
22
 
20
- def force_branch(branch)
21
- git = Git.open('test/git_root')
22
- git.reset_hard('HEAD')
23
- git.checkout branch.to_s, :force => true
23
+ def active_branch
24
+ file = File.open 'test/app_root/test.txt'
25
+ contents = file.read.strip
26
+ file.close
27
+ contents
24
28
  end
25
29
 
26
30
  # We have to rewrite the host constant in rack-test
@@ -34,8 +38,7 @@ class Test::Unit::TestCase
34
38
 
35
39
  def set_mock_request(addr, opts={})
36
40
  req = Rack::MockRequest.env_for "http://#{addr}", opts
37
- git = Divergence::GitManager.new(Divergence::Application.config)
38
- app.req = Divergence::RequestParser.new(req, git)
41
+ app.req = Divergence::RequestParser.new(req)
39
42
  end
40
43
 
41
44
  def mock_get(addr, params={})
@@ -63,7 +66,7 @@ end
63
66
 
64
67
  module Divergence
65
68
  class Application < Rack::Proxy
66
- attr_accessor :req
69
+ attr_accessor :req, :active_branch
67
70
 
68
71
  def perform_request(env)
69
72
  [200, {"Content-Type" => "text/html"}, ["Ohai"]]
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class WebhookTest < Test::Unit::TestCase
4
4
  def test_detect
5
- force_branch :master
5
+ mock_get "master.example.com"
6
6
  status, _, body = mock_webhook :master
7
7
 
8
8
  assert_equal 200, status
@@ -10,8 +10,7 @@ class WebhookTest < Test::Unit::TestCase
10
10
  end
11
11
 
12
12
  def test_ignore
13
- force_branch :master
14
- status, _, body = mock_webhook :branch1
13
+ status, _, body = mock_webhook 'webhook-ignore'
15
14
 
16
15
  assert_equal 200, status
17
16
  assert_equal ["IGNORE"], body
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: divergence
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-11 00:00:00.000000000 Z
12
+ date: 2012-10-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -59,22 +59,6 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: git
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :runtime
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
62
  - !ruby/object:Gem::Dependency
79
63
  name: json
80
64
  requirement: !ruby/object:Gem::Requirement
@@ -120,7 +104,6 @@ files:
120
104
  - .gitignore
121
105
  - Gemfile
122
106
  - LICENSE
123
- - LICENSE.txt
124
107
  - README.md
125
108
  - Rakefile
126
109
  - bin/divergence
@@ -129,6 +112,8 @@ files:
129
112
  - generators/files/config.rb
130
113
  - generators/files/config.ru
131
114
  - lib/divergence.rb
115
+ - lib/divergence/application.rb
116
+ - lib/divergence/cache_manager.rb
132
117
  - lib/divergence/config.rb
133
118
  - lib/divergence/git_manager.rb
134
119
  - lib/divergence/helpers.rb
@@ -139,7 +124,6 @@ files:
139
124
  - lib/rack_ssl_hack.rb
140
125
  - log/.gitkeep
141
126
  - public/404.html
142
- - test/app_root/test.txt
143
127
  - test/config.rb
144
128
  - test/config_test.rb
145
129
  - test/git_test.rb
@@ -171,7 +155,6 @@ signing_key:
171
155
  specification_version: 3
172
156
  summary: Map virtual host subdomains to git branches for testing
173
157
  test_files:
174
- - test/app_root/test.txt
175
158
  - test/config.rb
176
159
  - test/config_test.rb
177
160
  - test/git_test.rb
@@ -1,22 +0,0 @@
1
- Copyright (c) 2012 Ryan LeFevre
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1 +0,0 @@
1
- master