railsapp_factory 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,43 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ /vendor/bundle
5
+ .yardoc
6
+ Gemfile.lock
7
+
8
+ config/initializers/secret_token.rb
9
+ .config
10
+
11
+ InstalledFiles
12
+ .yardoc
13
+ _yardoc
14
+ coverage
15
+ doc/
16
+ lib/bundler/man
17
+ pkg
18
+ rdoc
19
+ spec/reports
20
+ test/tmp
21
+ test/version_tmp
22
+ tmp
23
+ /coverage/
24
+ /public/system/*
25
+ /spec/tmp/*
26
+
27
+ *.sassc
28
+ .sass-cache
29
+ /log/*
30
+ /db/*.sqlite3
31
+
32
+ capybara-*.html
33
+
34
+ .rspec
35
+ .rvmrc
36
+ .ruby-version
37
+
38
+ .project
39
+
40
+ rerun.txt
41
+ pickle-email-*.html
42
+
43
+ /bin
data/.travis.yml ADDED
@@ -0,0 +1,36 @@
1
+ language: ruby
2
+ notifications:
3
+ email:
4
+ on_success: change
5
+ on_failure: always
6
+
7
+ before_install:
8
+ - gem update --system $RUBYGEMS_VERSION
9
+
10
+ - gem --version
11
+ - gem install bundler
12
+ - bundle --version
13
+ - mkdir -p tmp/bundle
14
+
15
+ bundler_args: "--binstubs"
16
+
17
+ rvm:
18
+ # - 1.8.7 - include below so RUBYGEMS version gets set
19
+ - 1.9.2
20
+ - 1.9.3
21
+ - 2.0.0
22
+ - 2.1.0
23
+ - jruby-head
24
+ - rbx
25
+
26
+ script: bin/rake build spec install
27
+
28
+ matrix:
29
+ allow_failures:
30
+ # error: sqlite3-1.3.9/lib/sqlite3/sqlite3_native.so: undefined symbol: RBIGNUM_DIGITS
31
+ - rvm: rbx
32
+ include:
33
+ # set RUBYGEMS_VERSION=1.8.25 for ruby 1.8.7 to avoid "undefined method `source_index' for Gem:Module" errors
34
+ - rvm: 1.8.7
35
+ env: RUBYGEMS_VERSION=1.8.25
36
+
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in railsapp_factory.gemspec
4
+ gemspec
5
+
6
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ian Heggie
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.
data/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # RailsappFactory
2
+
3
+ Rails application factory to make testing gems against multiple versions easier
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'railsapp_factory'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install railsapp_factory
18
+
19
+ ## Usage
20
+
21
+ To get the list of available versions (that can be run with the ruby version you are currently running):
22
+
23
+ RailsappFactory.versions
24
+
25
+ Depending on the ruby version in use, it will suggest versions '2.3', '3.0', '3.1', '3.2' and '4.0'. The latest in each series will be downloaded. You can also specify a specific version, eg '3.2.8' or 'edge' (edge has to be selected manually as unforsean changes may break the standard build process).
26
+
27
+ The INTENT is to end up with:
28
+
29
+ To test a gem (health_check in this case), run:
30
+
31
+ RailsappFactory.versions.each do |version|
32
+ railsapp = RailsappFactory.new(version) # also accepts "edge"
33
+ railsapp.timeout = 300 # timeout operations after 300 seconds
34
+ railsapp.db = 'mysql2' # database gem to use
35
+ railsapp.template = File.expand_path('templates/add-file.rb', File.dirname(__FILE__)) # ie full path name
36
+ # OR
37
+ railsapp.template = "http://example.com/example.rb"
38
+
39
+ # you can also append to the template defined above, or start a custom template from scratch by using append_to_template
40
+ # A temp file is created containing the combined template information
41
+
42
+ railsapp.append_to_template <<-EOF
43
+ gem "my_gem_name", :path => '#{File.expand_path('templates/add-file.rb', '..')}'
44
+ bundle install
45
+ generate(:scaffold, "person name:string")
46
+ route "root to: 'people#index'"
47
+ rake("db:migrate")
48
+ EOF
49
+
50
+ # following commands return a struct with stdout, stderr and exit_status
51
+ # and an exception is raised if build fails
52
+
53
+ puts "Latest version in #{railsapp.release} series is #{railsapp.version}"
54
+
55
+ railsapp.build # run,rake,runner,console will all trigger this if you forget
56
+
57
+ railsapp.append_to_template 'gem "halo"'
58
+
59
+ railsapp.process_template # apply template with rake command
60
+
61
+ # runs an expression in runner and ruby respectively, and uses to_json to return the result.
62
+ # exceptions are passed through, except for syntax errors
63
+
64
+ railsapp.rails_eval 'Some.rails(code)' # with rails loaded
65
+ railsapp.ruby_eval 'Some.ruby(code)' # without rails (except for 2.3* which requires rails to pass results back)
66
+
67
+ railsapp.run
68
+
69
+ # check server is actually running
70
+ railsapp.alive?.should be_true
71
+
72
+ # some helpers for constructing urls (strings)
73
+ puts "home url: #{railsapp.url}"
74
+ puts "url: #{railsapp.url('/search', {:author => {:name => 'fred'}})"
75
+
76
+ puts "Instance of URI: #{railsapp.uri('/some/path', :name => 'value')}"
77
+
78
+ puts "port: #{railsapp.port}"
79
+
80
+ railsapp.stop
81
+
82
+ # override ENV passed to rails app processes
83
+ railsapp.override_ENV['EDITOR'] = 'vi'
84
+
85
+ railsapp.in_app do
86
+ # runs command in rails root dir without the extra environment variables bundler exec sets"
87
+ system 'some shell command'
88
+ end
89
+
90
+ railsapp.system_in_app 'another shell command'
91
+
92
+ railsapp.destroy
93
+ end
94
+
95
+ # removes all temp directories - TODO: stop any running servers
96
+ RailsappFactory.cleanup
97
+
98
+ If you use rvm (eg travis.ci) or rbenv (like I do), then you also go the other way,
99
+ and run you tests in a specific version of ruby (eg to use the later syntax), but build and/or run the rails app
100
+ with the various ruby versions you have installed.
101
+
102
+ It will attempt to find rvm / rbenv through environment variables first, the check the PATH, and lastly check the standard install directories under $HOME.
103
+ This handles RubyMine's clearing of environment variables, running rbenv or rvm in command mode only whilst running the system ruby.
104
+
105
+ RailsappFactory.rubies # lists all ruby versions available (in the format the version manager prefers)
106
+ RailsappFactory.rvm? # is RVM available
107
+ RailsappFactory.rbenv? # is rbenv available
108
+ RailsappFactory.has_ruby_version_manager? # either available?
109
+ RailsappFactory.using_system_ruby? # simple check that there are no rvm or rbenv specific directories in PATH
110
+
111
+ # example without having to build the actual rails app (run ruby commands)
112
+
113
+ RailsappFactory.rubies.each do |ruby_v|
114
+ it "provides a command prefix that will run ruby #{ruby_v}" do
115
+ prefix = RailsappFactory.ruby_command_prefix(ruby_v)
116
+ actual_ruby_v=`#{prefix} ruby -v`
117
+ end
118
+ end
119
+
120
+ ### Future Development
121
+
122
+ At the moment the rubies system isn't smart enough to work out which ruby works with which rails versions,
123
+ nor know the jruby and rbx switches that change the language modes. I intend to develop that area further.
124
+ Suggestions welcome if checking RUBY_VERSION is sufficient, along with checking if the ruby_version changes
125
+ from the default with `JRUBY_OPTS=--1.9, --1.8, --2.0` as well as `RBXOPT=-X18, -X19, -X20, -X21`,
126
+ or if I need to do more.
127
+
128
+ I am thinking of adding multiple entries in the rubies list for rbx / jruby if the env variables trigger a change in
129
+ RUBY_VERSION, eg:
130
+ * jruby-1.7.9
131
+ * jruby-1.7.9/18mode
132
+ * jruby-1.7.9/19mode
133
+ * jruby-1.7.9/20mode
134
+
135
+ # example for a rail application
136
+
137
+ @factory = RailsappFactory.new # chooses the most recent rails version compatible with RUBY_VERSION
138
+
139
+ @factory.rubies.each do |ruby_v|
140
+ @factory.use(ruby_v)
141
+ actual_ruby_v = @factory.rails_eval('RUBY_VERSION')
142
+ puts "Using #{@factory.using} ruby"
143
+ end
144
+ @factory.use(nil) # revert to the default ruby (in PATH)
145
+
146
+ # You can also pass use a block, and it will revert the ruby version afterwards
147
+ @factory.use(ruby_v)
148
+ actual_ruby_v = @factory.rails_eval('RUBY_VERSION')
149
+ end
150
+
151
+
152
+ I am considering get/put like integration tests have, but requires some thought first to be non rails version specific
153
+
154
+ #TODO: railsapp.get("/some/path") - returns status same as get in tests
155
+ #TODO: railsapp.post("/another/path", :author => { :name => 'fred' } ) - returns status same as post in tests
156
+
157
+
158
+ ## Contributing
159
+
160
+ 1. Fork it
161
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
162
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
163
+ 4. Push to the branch (`git push origin my-new-feature`)
164
+ 5. Create new Pull Request
165
+
166
+ ## License
167
+
168
+ MIT - See LICENSE.txt
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ # If you want to make this the default task
8
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ class RailsappFactory
2
+
3
+ class BuildError < RuntimeError
4
+
5
+ end
6
+
7
+ end
@@ -0,0 +1,141 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+ require 'railsapp_factory'
4
+
5
+ class RailsappFactory
6
+ module BuildMethods
7
+
8
+ # class variables used in module:
9
+ # @base_dir
10
+ # @built
11
+ # @bundled
12
+ # @root
13
+ # @release
14
+
15
+ def destroy
16
+ if @base_dir
17
+ stop
18
+ # keep last built example in last.VERSION
19
+ FileUtils.rm_rf "#{TMPDIR}/last.#{@version}"
20
+ FileUtils.mv @base_dir, "#{TMPDIR}/last.#{@version}" if File.directory?(@base_dir)
21
+ FileUtils.rm_rf @base_dir # to be sure, to be sure!
22
+ end
23
+ @base_dir = nil
24
+ @built = false
25
+ @bundled = false
26
+ @root = nil
27
+ @release = nil
28
+ end
29
+
30
+ def build
31
+ if built?
32
+ self.logger.info "Already built Rails #{@version} app in directory #{root}"
33
+ process_template
34
+ return false
35
+ end
36
+ self.use_template 'templates/add_json_pure.rb'
37
+ if self.version =~ /^2/
38
+ self.use_template 'templates/use_bundler_with_rails23.rb'
39
+ else
40
+ self.use_template 'templates/add_necessary_gems.rb'
41
+ end
42
+ new_arg = @version =~ /^2/ ? '' : ' new'
43
+ other_args = @version =~ /^2/ ? '' : '--no-rc --skip-bundle --force'
44
+ other_args <<= ' --edge' if @version == 'edge'
45
+ other_args <<= " -m #{self.template}" if self.template
46
+
47
+ self.logger.info "Creating Rails #{@version} app in directory #{root}"
48
+ unless in_app('.') { Kernel.system "sh -xc '#{rails_command} #{new_arg} #{root} -d #{db} #{other_args}' #{append_log 'rails_new.log'}" }
49
+ @built = true # avoid repeated build attempts
50
+ raise BuildError.new("rails #{new_arg}railsapp failed #{see_log 'rails_new.log'}")
51
+ end
52
+ @built = true
53
+ clear_template
54
+ expected_file = File.join(root, 'config', 'environment.rb')
55
+ raise BuildError.new("error building railsapp - missing #{expected_file}") unless File.exists?(expected_file)
56
+
57
+ command = "sh -xc 'bundle install --binstubs .bundle/bin' #{append_log 'bundle.log'}"
58
+ self.logger.info "Installing gems with binstubs using command: #{command}"
59
+ unless system_in_app command
60
+ raise BuildError.new("bundle install returned exit status #{$?} #{see_log 'bundle.log'}")
61
+ end
62
+ @bundled = true
63
+ raise BuildError.new("error installing gems - Gemfile.lock missing #{see_log 'bundle.log'}") unless File.exists?(File.join(root, 'Gemfile.lock'))
64
+ true
65
+ end
66
+
67
+ def built?
68
+ @built
69
+ end
70
+
71
+ def bundled?
72
+ @bundled
73
+ end
74
+
75
+ # release installed as reported by the rails command itself
76
+ def release
77
+ @release ||= begin
78
+ cmd = rails_command
79
+ self.logger.debug "Getting release using command: #{cmd} '-v'"
80
+ r = in_app(RailsappFactory::TMPDIR) { `#{cmd} '-v'` }.chomp.sub(/^Rails */, '')
81
+ self.logger.debug "Release: #{r}"
82
+ r
83
+ end
84
+ end
85
+
86
+ def root
87
+ @root = File.join(base_dir, 'railsapp')
88
+ end
89
+
90
+ private
91
+
92
+ def rails_command
93
+ rails_cmd_dir = "#{RailsappFactory::TMPDIR}/rails-#{@version}"
94
+ rails_path = "#{rails_cmd_dir}/bin/rails"
95
+ #command = '"%s" "%s"' % [Gem.ruby, rails_path]
96
+ command = rails_path
97
+ unless File.exists?(rails_path)
98
+ self.logger.info "Creating bootstrap Rails #{@version} as #{rails_path}"
99
+ FileUtils.rm_rf rails_cmd_dir
100
+ FileUtils.mkdir_p rails_cmd_dir
101
+ Dir.chdir(rails_cmd_dir) do
102
+ create_Gemfile
103
+ Bundler.with_clean_env do
104
+ Kernel.system "sh -xc '#{bundle_command} install --binstubs' #{append_log 'bundle.log'}"
105
+ end
106
+ end
107
+ unless File.exists?(rails_path)
108
+ raise BuildError.new("Error getting rails_command: (#{rails_path})")
109
+ end
110
+ end
111
+ command
112
+ end
113
+
114
+ def create_Gemfile
115
+ version_spec = if @version == 'edge'
116
+ "github: 'rails/rails'"
117
+ elsif @version == '2.3-lts'
118
+ ":git => 'git://github.com/makandra/rails.git', :branch => '2-3-lts'"
119
+ elsif @version =~ /\.\d+\./
120
+ "'#{@version}'"
121
+ else
122
+ "'~> #{@version}.0'"
123
+ end
124
+ gemfile_content = <<-EOF
125
+ source '#{@gem_source}'
126
+ gem 'rails', #{version_spec}
127
+ EOF
128
+
129
+ File.open('Gemfile', 'w') { |f| f.puts gemfile_content }
130
+ self.logger.debug "Created Gemfile with: <<\n#{gemfile_content}>>"
131
+ end
132
+
133
+ def base_dir
134
+ @base_dir ||= begin
135
+ FileUtils.mkdir_p RailsappFactory::TMPDIR
136
+ Dir.mktmpdir("app-#{self.version.gsub(/\W/, '_')}-", RailsappFactory::TMPDIR)
137
+ end
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,155 @@
1
+ require 'cgi'
2
+ require 'fileutils'
3
+
4
+ class RailsappFactory
5
+ module ClassMethods
6
+ # encodes url query arguments, incl nested
7
+ def encode_query(args, prefix = '', suffix = '')
8
+ query = ''
9
+ args.each do |key, value|
10
+ if value.is_a?(Hash)
11
+ query <<= encode_query(value, "#{prefix}#{key}[", "]#{suffix}")
12
+ else
13
+ query <<= '&' << CGI::escape(prefix + key.to_s + suffix) << '=' << CGI::escape(value.to_s)
14
+ end
15
+ end if args
16
+ if prefix == ''
17
+ query.sub(/^&/, '?')
18
+ else
19
+ query
20
+ end
21
+ end
22
+
23
+ def cleanup
24
+ FileUtils.rm_rf RailsappFactory::TMPDIR
25
+ end
26
+
27
+ def versions(ruby_v = RUBY_VERSION)
28
+ case (ruby_v.to_s)
29
+ when /^1\.8\.6/
30
+ %w{2.3}
31
+ when /^1\.8\.7/
32
+ %w{2.3 2.3-lts 3.0 3.1 3.2}
33
+ when /^1\.9\.1/
34
+ %w{2.3}
35
+ when /^1\.9\.2/
36
+ %w{3.0 3.1 3.2}
37
+ when /^1\.9\.3/
38
+ %w{3.0 3.1 3.2 4.0}
39
+ when /^2\.[01]/
40
+ %w{4.0}
41
+ when /^1\./
42
+ []
43
+ when ''
44
+ # all
45
+ %w{2.3 2.3-lts 3.0 3.1 3.2 4.0}
46
+ else
47
+ %w{4.0} # a guess!
48
+ end
49
+ end
50
+
51
+ def rubies # (rails_v = nil)
52
+ find_ruby_version_manager
53
+ ruby_command_prefix_template
54
+ result = if @@rbenv_path
55
+ `#{@@rbenv_path} versions --bare`
56
+ elsif @@rvm_path
57
+ `#{@@rvm_path} list strings`
58
+ else
59
+ ''
60
+ end.split(/\r?\n/)
61
+ # TODO: rework this to run each one and extract the RUBY_VERSION to work out what is compatible
62
+ # TODO: extend this with JRUBY_OPTS=--1.9, --1.8, --2.0 as well as RBXOPT=-X18, -X19, -X20, -X21 and check which ones actually change the RUBY_VERSION value
63
+ # TODO: rbx is outputting an extra nil as it is running as irb sometimes .. test this
64
+ # if rails_v.nil?
65
+ # result
66
+ #else
67
+ # rails_v_compare = rails_v.sub(/^(\d+\.\d+).*?(-lts)?$/, '\1\2')
68
+ # result.select do |ruby_v|
69
+ # rails_v.nil? || versions(ruby_v).include?(rails_v_compare)
70
+ # end
71
+ #end
72
+ end
73
+
74
+ def ruby_command_prefix(ruby_v = nil)
75
+ if ruby_v.to_s == ''
76
+ ''
77
+ else
78
+ ruby_command_prefix_template % ruby_v.to_s
79
+ end
80
+ end
81
+
82
+ def rbenv?
83
+ find_ruby_version_manager
84
+ @@rbenv_path
85
+ end
86
+
87
+ def rvm?
88
+ find_ruby_version_manager
89
+ @@rvm_path
90
+ end
91
+
92
+ def has_ruby_version_manager?
93
+ find_ruby_version_manager != ''
94
+ end
95
+
96
+ def using_system_ruby?
97
+ ENV['PATH'] !~ /\/\.?rbenv\/versions\// && ENV['PATH'] !~ /\/\.?rvm\/rubies\//
98
+ end
99
+
100
+ private
101
+
102
+ def list_rubies
103
+ find_ruby_version_manager
104
+ if @@rbenv_path
105
+ `#{@@rbenv_path} versions --bare`
106
+ elsif @@rvm_path
107
+ `#{@@rvm_path} list strings`
108
+ else
109
+ ''
110
+ end.split(/\r?\n/)
111
+ end
112
+
113
+ def ruby_command_prefix_template
114
+ @@ruby_command_prefix_template ||= begin
115
+ find_ruby_version_manager
116
+ if @@rbenv_path
117
+ "env 'RBENV_VERSION=%s' #{@@rbenv_path} exec"
118
+ elsif @@rvm_path
119
+ "#{@@rvm_path} '%s' do"
120
+ else
121
+ ''
122
+ end
123
+ end
124
+ end
125
+
126
+
127
+ def find_ruby_version_manager
128
+ @@found_ruby_version_manager ||= begin
129
+ @@rbenv_path = ENV['RBENV_ROOT'] ? "#{ENV['RBENV_ROOT']}/bin/rbenv" : nil
130
+ @@rvm_path = ENV['rvm_path'] ? "#{ENV['rvm_path']}/bin/rvm" : nil
131
+ unless @@rbenv_path || @@rvm_path
132
+ # RubyMine removes RBENV_PATH when a rbenv environment is selected
133
+ ENV['PATH'].split(':').each do |exec_path|
134
+ @@rbenv_path = "#{$1}/bin/rbenv" if exec_path =~ /^(.*\/\.?rbenv)\/(bin|versions)/
135
+ @@rvm_path = "#{$1}/bin/rbenv" if exec_path =~ /^(.*\/\.?rvm)\/(bin|rubies)/
136
+ break if @@rbenv_path || @@rvm_path
137
+ end
138
+ # In case we are running from system ruby and the shell environment is not set
139
+ unless @@rbenv_path || @@rvm_path
140
+ if File.exists? "#{ENV['HOME']}/.rbenv/bin/rbenv"
141
+ @@rbenv_path = "#{ENV['HOME']}/.rbenv/bin/rbenv"
142
+ elsif File.exists? "#{ENV['HOME']}/.rvm/bin/rvm"
143
+ @@rvm_path = "#{ENV['HOME']}/.rvm/bin/rvm"
144
+ end
145
+ end
146
+ end
147
+ @@rbenv_path = nil unless @@rbenv_path && File.exists?(@@rbenv_path)
148
+ @@rvm_path = nil if @@rbenv_path || !@@rvm_path || !File.exists?(@@rvm_path)
149
+ @@rbenv_path || @@rvm_path || ''
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ end