sfb_scripts 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7cbc870683c0380827cabc69fd8840684dc81abc
4
+ data.tar.gz: e129a948b2183ffa885bae660d5dcadfd32e0977
5
+ SHA512:
6
+ metadata.gz: 2c2c5d7cf13aa8a9633adf665571a9279b82fca2df14fa4360d1ba282ad5a6550ee0059f09ae3f5435efa180742884c5c3245014c8f5b64fcc83e6ea6a214e65
7
+ data.tar.gz: 8cf02cba029addbbef7fc424f4d2cf305adf20b1c5c06a0966031e34481edc8b3954ba3a5003440c441086deeb632bff7620080f755ff9c7354df7e07a04e4fe
data/bin/app_up ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/upper'
4
+ require 'thor'
5
+
6
+ class CLI < Thor
7
+
8
+ #
9
+ # REBASE
10
+ #
11
+
12
+ desc "rebase", "Rebase your commits onto master. Bundle installs and migrates as needed. Will terminate if conflicts are found."
13
+ option :loud, :type => :boolean, :desc => 'Pipe output to terminal or not (output is always piped to /tmp/up.log)'
14
+ option :all, :type => :boolean, :desc => "Don't update the repo, just bundle and migrate everywhere."
15
+
16
+ def up
17
+ if options[:all]
18
+ Upper.no_git(options)
19
+ else
20
+ Upper.rebase_on_master!(options)
21
+ end
22
+ end
23
+
24
+ desc "install_hooks", "Install a pre-push git hook that will not let you push to remote master."
25
+ def install_hooks
26
+ Upper.install_hooks(options)
27
+ end
28
+
29
+ desc "pre_push_hook", "Deny destructive actions to the remote master."
30
+ def pre_push_hook(git_command)
31
+ Upper.pre_push_hook(git_command, options)
32
+ end
33
+
34
+ default_task :up
35
+ end
36
+
37
+ CLI.start(ARGV)
data/bin/test_runner ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/tester'
4
+ require 'thor'
5
+
6
+ class CLI < Thor
7
+
8
+ #
9
+ # run
10
+ #
11
+ desc "status", "Find dirty tests in your git status and run them."
12
+ option :all_engines, :type => :boolean, :desc => 'Run all tests identified, regardless of engine'
13
+ option :no_selenium, :type => :boolean, :desc => 'Ignore selenium'
14
+ def status
15
+ Tester.status(options)
16
+ end
17
+
18
+ #
19
+ # run
20
+ #
21
+ desc "find", <<-DESC
22
+ Find tests and run them. By trying to match an individual test or the name of a test file(s).
23
+ DESC
24
+ def find(*inputs)
25
+ Tester.find(inputs, options)
26
+ end
27
+
28
+ desc "status_check", "Verify that you don't edit a file without editing its corresponding test file."
29
+ option :confirm_exit_status, :type => :boolean, :desc => 'Asks user whether to exit with status 0 or 1. Used in the pre-commit hook'
30
+ def status_check
31
+ Tester.status_check(options)
32
+ end
33
+
34
+ default_task :status
35
+
36
+ end
37
+
38
+ CLI.start(ARGV)
@@ -0,0 +1,47 @@
1
+ require_relative 'repo'
2
+
3
+ class ActiveRepo < Repo
4
+
5
+ def rebase_on_master!
6
+ up do
7
+ # will raise an error with merge conflicts
8
+ begin
9
+ shell.run "git pull --rebase origin master"
10
+ rescue ShellRunner::CommandFailureError
11
+ puts "Unable to rebase. Maybe you need to stash local changes, or there are rebase conflicts"
12
+ puts `git status`
13
+ exit
14
+ end
15
+ end
16
+ end
17
+
18
+ def up_master!
19
+ move_to_master!
20
+ rebase_on_master!
21
+ end
22
+
23
+ def up
24
+ @old_sha = current_sha
25
+ yield
26
+ @new_sha = current_sha
27
+ end
28
+
29
+ def pull_origin_master!
30
+ up do
31
+ fetch_origin
32
+ reset_hard_origin_master!
33
+ end
34
+ end
35
+
36
+ def fetch_origin
37
+ shell.run 'git fetch origin'
38
+ end
39
+
40
+ def reset_hard_origin_master!
41
+ shell.run "git reset --hard origin/master"
42
+ end
43
+
44
+ def move_to_master!
45
+ shell.run "git checkout master"
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ class BundleManager
2
+ attr_accessor :shell, :repo
3
+
4
+ def initialize(repo: raise, shell: raise)
5
+ @shell = shell
6
+ @repo = repo
7
+ end
8
+
9
+ def bundle_where_necessary
10
+ find("Gemfile.lock").each do |gemfile_lock|
11
+ if repo.changed?(gemfile_lock)
12
+ bundle(directory_of(gemfile_lock))
13
+ end
14
+ end
15
+ end
16
+
17
+ def bundle(gemfile_directory)
18
+ begin
19
+ shell.run "bundle install --local", dir: gemfile_directory
20
+ rescue ShellRunner::CommandFailureError
21
+ puts 'trying without --local'
22
+ shell.run "bundle install", dir: gemfile_directory
23
+ end
24
+ end
25
+
26
+ def find(file_name)
27
+ Dir.glob("**/#{file_name}")
28
+ end
29
+
30
+ def directory_of(file_path)
31
+ File.dirname(file_path)
32
+ end
33
+
34
+ end
@@ -0,0 +1,36 @@
1
+ class HookManager
2
+
3
+ def self.install!(env)
4
+ new(env).install!
5
+ end
6
+
7
+ attr_reader :shell, :repo
8
+
9
+ def initialize(env)
10
+ @shell = env[:shell]
11
+ @repo = env[:repo]
12
+ end
13
+
14
+ def is_installed?
15
+ File.file?('.git/hooks/pre-push')
16
+ end
17
+
18
+ def install!
19
+ return if is_installed?
20
+
21
+ create_file
22
+ make_executable
23
+ end
24
+
25
+ private
26
+
27
+ def create_file
28
+ shell.run %{echo 'app_up pre_push_hook "$(ps -ocommand= -p $PPID)"' > .git/hooks/pre-push}
29
+ shell.run %{echo 'test_runner status_check --confirm_exit_status' > .git/hooks/pre-commit}
30
+ end
31
+
32
+ def make_executable
33
+ shell.run "chmod +x .git/hooks/pre-push"
34
+ shell.run "chmod +x .git/hooks/pre-commit"
35
+ end
36
+ end
data/lib/lazy_repo.rb ADDED
@@ -0,0 +1,9 @@
1
+ require_relative 'repo'
2
+
3
+ class LazyRepo < Repo
4
+
5
+ def files_changed
6
+ all_files
7
+ end
8
+
9
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'shell_runner'
2
+
3
+ class LoudShellRunner < ShellRunner
4
+
5
+ def run(*args)
6
+ super(*args).tap do |results|
7
+ puts results
8
+ end
9
+ end
10
+ end
data/lib/migrator.rb ADDED
@@ -0,0 +1,28 @@
1
+ class Migrator
2
+ attr_accessor :shell, :repo
3
+
4
+ def initialize(repo: raise, shell: raise)
5
+ @shell = shell
6
+ @repo = repo
7
+ end
8
+
9
+ def migrate_where_necessary
10
+ directories_to_migrate.each do |dir|
11
+ shell.run "bundle exec rake db:create db:migrate", dir: dir
12
+ shell.run "RAILS_ENV=test bundle exec rake db:create db:migrate", dir: dir
13
+ end
14
+ end
15
+
16
+ def directories_to_migrate
17
+ migrate_dirs = repo.files_changed.select {|f| f.match("/migrate/") }.map {|f| File.dirname(f) }.uniq
18
+ migrate_dirs.select {|d| in_rack_application?(d) };
19
+ end
20
+
21
+ private
22
+
23
+ def in_rack_application?(migrate_dir)
24
+ root_dir = migrate_dir.gsub(/db\/migrate$/, '')
25
+ File.file?("#{root_dir}/config.ru")
26
+ end
27
+
28
+ end
@@ -0,0 +1,85 @@
1
+ require_relative 'shell_runner'
2
+ require_relative 'loud_shell_runner'
3
+ require_relative 'repo'
4
+ require_relative 'lazy_repo'
5
+ require_relative 'active_repo'
6
+ require_relative 'migrator'
7
+ require_relative 'bundle_manager'
8
+ require_relative 'test_runner'
9
+
10
+ class NeedsManager
11
+
12
+ def self.configure(task, needs, options)
13
+ new(task, needs, options).configure
14
+ end
15
+
16
+ attr_reader :needs, :options, :env, :log_file
17
+ def initialize(task, needs, options)
18
+ @log_file = log_file_for(task)
19
+ @needs = needs
20
+ @options = options
21
+ @env = {}
22
+ end
23
+
24
+ def configure
25
+ set_working_directory
26
+
27
+ create_shell
28
+ create_repo if needs.include? :repo
29
+ create_bundler if needs.include? :bundler
30
+ create_migrator if needs.include? :migrator
31
+ create_test_runner if needs.include? :test_runner
32
+
33
+ return env
34
+ end
35
+
36
+ def set_working_directory
37
+ @working_directory = Repo.root_dir
38
+ Dir.chdir(@working_directory)
39
+ end
40
+
41
+ def create_shell
42
+ env[:shell] = shell_class.new(log_file, @working_directory)
43
+ end
44
+
45
+ def shell_class
46
+ if options[:loud]
47
+ LoudShellRunner
48
+ else
49
+ ShellRunner
50
+ end
51
+ end
52
+
53
+ def create_repo
54
+ env[:repo] = repo_class.new(shell: env[:shell])
55
+ end
56
+
57
+ def repo_class
58
+ if options[:repo_type] == :active
59
+ ActiveRepo
60
+ elsif options[:repo_type] == :lazy
61
+ LazyRepo
62
+ else
63
+ Repo
64
+ end
65
+ end
66
+
67
+ def create_bundler
68
+ env[:bundler] = BundleManager.new(shell: env[:shell], repo: env[:repo])
69
+ end
70
+
71
+ def create_migrator
72
+ env[:migrator] = Migrator.new(shell: env[:shell], repo: env[:repo])
73
+ end
74
+
75
+ def create_test_runner
76
+ env[:test_runner] = TestRunner.new(
77
+ shell: env[:shell],
78
+ all_engines: options[:all_engines]
79
+ )
80
+ end
81
+
82
+ def log_file_for(task)
83
+ "/tmp/#{task}.log"
84
+ end
85
+ end
@@ -0,0 +1,31 @@
1
+ class PrePushHook
2
+
3
+ def self.check(command, env)
4
+ new(command, env).check
5
+ end
6
+
7
+ attr_reader :shell, :repo, :push_command
8
+ def initialize(command, env)
9
+ @shell = env[:shell]
10
+ @repo = env[:repo]
11
+ @push_command = command
12
+ end
13
+
14
+ def check
15
+ if affects_master? && is_destructive?
16
+ shell.warn "[Policy] Don't force push or delete master. (Denied by pre-push hook)"
17
+ exit 1
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def affects_master?
24
+ push_command.match(/master/) || (repo.current_branch == 'master')
25
+ end
26
+
27
+ def is_destructive?
28
+ push_command.match(/-f|delete|force| :master/)
29
+ end
30
+
31
+ end
data/lib/repo.rb ADDED
@@ -0,0 +1,69 @@
1
+ class Repo
2
+
3
+ def self.root_dir
4
+ @root_dir ||= %x[ git rev-parse --show-toplevel ].chomp
5
+ end
6
+
7
+ attr_reader :shell
8
+
9
+ def initialize(shell: shell)
10
+ @shell = shell
11
+ end
12
+
13
+ def files_changed
14
+ @files_changed ||= (shell.run "git diff --name-only #{@old_sha}").split("\n")
15
+ end
16
+
17
+ def changed?(file_path)
18
+ files_changed.include? file_path
19
+ end
20
+
21
+ def all_files
22
+ @all_files ||= shell.run("git ls-tree --full-tree -r HEAD --name-only").split("\n")
23
+ end
24
+
25
+ def find_files(pattern)
26
+ shell.run("git ls-files '*#{pattern}*'").split("\n")
27
+ end
28
+
29
+ def status_files
30
+ statii = shell.run("git status -s").split("\n")
31
+ r = statii.map do |status|
32
+ status.strip!
33
+ if status[0] == 'D'
34
+ nil
35
+ else
36
+ status.split(' ').last
37
+ end
38
+ end.compact
39
+ end
40
+
41
+ def grep(regex, file_pattern: '*')
42
+ results = shell.run("git grep '#{regex}' -- '#{file_pattern}'").split("\n")
43
+ results.map do |result|
44
+ interpret_grep_result(result)
45
+ end
46
+ end
47
+
48
+ def current_branch
49
+ shell.run 'git rev-parse --abbrev-ref HEAD'
50
+ end
51
+
52
+ private
53
+
54
+ def interpret_grep_result(grep_result)
55
+ splits = grep_result.split(/:/)
56
+ file = splits.shift
57
+ line = splits.join(':')
58
+
59
+ {
60
+ :file => file,
61
+ :line => line,
62
+ }
63
+ end
64
+
65
+ def current_sha
66
+ shell.run "git rev-parse HEAD"
67
+ end
68
+
69
+ end
@@ -0,0 +1,70 @@
1
+ require_relative 'string_extension'
2
+
3
+ class ShellRunner
4
+ CommandFailureError = Class.new(StandardError)
5
+
6
+ attr_accessor :working_directory, :log_path
7
+
8
+ def initialize(log_path, working_directory)
9
+ @working_directory = working_directory
10
+ @queue = ''
11
+ @log_path = log_path
12
+ reset_log
13
+ end
14
+
15
+ def run(cmd, dir: working_directory)
16
+ command = "cd #{dir} && #{cmd}"
17
+ puts command
18
+ log command
19
+ %x{ set -o pipefail && #{command} 2>> #{log_path} | tee -a #{log_path} }.chomp.tap do
20
+ raise CommandFailureError, "The following command has failed: #{command}. See #{log_path} for a full log." if ($?.exitstatus != 0)
21
+ end
22
+ end
23
+
24
+ def exec(cmd, dir: working_directory)
25
+ command = "cd #{dir} && #{cmd}"
26
+ notify "\n#{command}"
27
+ Kernel.exec command
28
+ end
29
+
30
+ def enqueue(cmd, dir: working_directory)
31
+ command = "cd #{dir} && #{cmd} && cd -"
32
+ @queue += "#{command};\n"
33
+ end
34
+
35
+ def confirm?(question)
36
+ warn "#{question} [Yn]"
37
+ answer = STDIN.gets.strip.downcase
38
+ return answer != 'n'
39
+ end
40
+
41
+ def deny?(question)
42
+ ! confirm?(question)
43
+ end
44
+
45
+ def exec_queue
46
+ notify 'running: '
47
+ notify ''
48
+ notify @queue
49
+ Kernel.exec @queue
50
+ end
51
+
52
+ def warn(msg)
53
+ log msg
54
+ puts msg.red
55
+ end
56
+
57
+ def notify(msg)
58
+ log msg
59
+ puts msg.yellow
60
+ end
61
+
62
+ def log(msg)
63
+ %x{echo "#{msg}" >> #{log_path}}
64
+ end
65
+
66
+ def reset_log
67
+ %x{echo "" > #{log_path}}
68
+ end
69
+
70
+ end
@@ -0,0 +1,62 @@
1
+ class StatusChecker
2
+ def self.report(env, confirm_exit_status)
3
+ new(env, confirm_exit_status).report
4
+ end
5
+
6
+ attr_reader :repo, :shell, :untested_files
7
+ def initialize(env, confirm_exit_status)
8
+ @repo = env[:repo]
9
+ @shell = env[:shell]
10
+ @untested_files = []
11
+ @confirm_exit_status = confirm_exit_status
12
+ end
13
+
14
+ def report
15
+ non_test_files.each do |file|
16
+ if ! test_files.include? "#{file}_test"
17
+ untested_files << full_path_by_basename(file)
18
+ end
19
+ end
20
+
21
+ if untested_files.empty?
22
+ shell.notify "All ruby files are tested!"
23
+ exit 0
24
+ else
25
+ shell.warn "The following files have changed without being tested:\n\n#{untested_files.join("\n")}"
26
+
27
+ STDIN.reopen('/dev/tty')
28
+ if confirm_exit_status? && shell.confirm?("\nDo you still wish to commit?")
29
+ exit 0
30
+ else
31
+ exit 1
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ private
38
+
39
+ def test_files
40
+ file_names.select {|f| f.match(/_test$/) }
41
+ end
42
+
43
+ def non_test_files
44
+ file_names.reject {|f| f.match(/_test$/) }
45
+ end
46
+
47
+ def file_names
48
+ @file_names ||= files.select {|f| f.match(/\.rb$/)}.map {|f| File.basename(f, '.rb') }
49
+ end
50
+
51
+ def files
52
+ @files ||= repo.status_files
53
+ end
54
+
55
+ def full_path_by_basename(file)
56
+ files.select {|f| File.basename(f, '.rb') == file }.first
57
+ end
58
+
59
+ def confirm_exit_status?
60
+ @confirm_exit_status
61
+ end
62
+ end
@@ -0,0 +1,22 @@
1
+ class String
2
+ # colorization
3
+ def colorize(color_code)
4
+ "\e[#{color_code}m#{self}\e[0m"
5
+ end
6
+
7
+ def red
8
+ colorize(31)
9
+ end
10
+
11
+ def green
12
+ colorize(32)
13
+ end
14
+
15
+ def yellow
16
+ colorize(33)
17
+ end
18
+
19
+ def pink
20
+ colorize(35)
21
+ end
22
+ end
data/lib/test_case.rb ADDED
@@ -0,0 +1,27 @@
1
+ class TestCase
2
+ TestDirectoryError = Class.new(StandardError)
3
+
4
+ attr_reader :working_dir, :relative_path, :test_name, :full_path
5
+
6
+ def initialize(full_path: raise, test_name: '')
7
+ @test_name = test_name
8
+ @full_path = full_path
9
+ end
10
+
11
+ def working_dir
12
+ @working_dir ||=
13
+ if full_path.match(/^(.*)test\//)
14
+ "#{full_path.match(/^(.*)test\//)[1]}"
15
+ else
16
+ raise TestDirectoryError.new("Can't find test's working directory")
17
+ end
18
+ end
19
+
20
+ def relative_path
21
+ @relative_path ||= full_path.gsub(/^#{working_dir}/, '') || raise_file_path_error
22
+ end
23
+
24
+ def raise_file_path_error
25
+ raise TestDirectoryError.new("Can't find test's relative path")
26
+ end
27
+ end
@@ -0,0 +1,105 @@
1
+ require_relative 'test_case'
2
+
3
+ class TestCollection
4
+
5
+ MultipleWorkingDirectoriesError = Class.new(StandardError)
6
+
7
+ def self.parse(grep_result)
8
+ new(grep_result[:file], line: grep_result[:line]).parse
9
+ end
10
+
11
+
12
+ def self.from_file_path(file_path)
13
+ new(file_path).from_file_path
14
+ end
15
+
16
+ attr_reader :tests
17
+
18
+ def initialize(tests_data)
19
+ @tests = tests_data.map do |test_data|
20
+ create_test_case(test_data)
21
+ end.compact
22
+ end
23
+
24
+ def empty?
25
+ tests.empty?
26
+ end
27
+
28
+ def present?
29
+ ! empty?
30
+ end
31
+
32
+ def size
33
+ tests.size
34
+ end
35
+
36
+ def first
37
+ tests.first
38
+ end
39
+
40
+ def [](*args)
41
+ tests[*args]
42
+ end
43
+
44
+ def in_one_file?
45
+ full_paths.size == 1
46
+ end
47
+
48
+ def in_one_engine?
49
+ working_dirs.size == 1
50
+ end
51
+
52
+ def full_paths
53
+ @full_paths ||= tests.map {|t| t.full_path }.uniq
54
+ end
55
+
56
+ def relative_paths
57
+ @relative_paths ||= tests.map {|t| t.relative_path }.uniq
58
+ end
59
+
60
+ def working_dirs
61
+ @working_dirs ||= tests.map {|t| t.working_dir }.uniq
62
+ end
63
+
64
+ def relative_paths_in(working_directory)
65
+ tests.select {|t| t.working_dir == working_directory}.map {|t| t.relative_path }.uniq
66
+ end
67
+
68
+ def include_selenium?
69
+ ! selenium_tests.empty?
70
+ end
71
+
72
+ def remove_selenium!
73
+ @tests = tests - selenium_tests
74
+ end
75
+
76
+ def selenium_tests
77
+ tests.select {|t| t.full_path.match(/selenium/)}
78
+ end
79
+
80
+ def working_dir
81
+ raise MultipleWorkingDirectoriesError.new("Can't run tests for more than one engine") unless working_dirs.size == 1
82
+
83
+ return working_dirs.first
84
+ end
85
+
86
+ private
87
+
88
+ def find_test_name(grepped_line)
89
+ return nil unless grepped_line
90
+ grepped_line.strip.gsub(/^\s*def /, '').strip
91
+ end
92
+
93
+ def create_test_case(test_data)
94
+ file_path = test_data[:file]
95
+ test_name = find_test_name(test_data[:line])
96
+ return nil if ! file_path.match(/_test\.rb/)
97
+ return nil if (test_name && ! test_name.match(/^test_/))
98
+
99
+ TestCase.new(
100
+ full_path: file_path,
101
+ test_name: test_name
102
+ )
103
+ end
104
+
105
+ end
@@ -0,0 +1,56 @@
1
+ require_relative 'test_collection'
2
+
3
+ class TestFileRunner
4
+
5
+ def self.find(inputs, env)
6
+ new(env, false).find(inputs)
7
+ end
8
+
9
+ def self.status(env, ignore_selenium=false)
10
+ new(env, ignore_selenium).status
11
+ end
12
+
13
+ attr_reader :repo, :shell, :test_runner, :tests, :ignore_selenium
14
+ def initialize(env, ignore_selenium)
15
+ @repo = env[:repo]
16
+ @shell = env[:shell]
17
+ @test_runner = env[:test_runner]
18
+ @ignore_selenium = ignore_selenium
19
+ end
20
+
21
+ def find(inputs)
22
+ files = []
23
+ inputs.each {|input| files << repo.find_files(input).map {|f| {:file => f} } }
24
+ files.flatten!
25
+ @tests = TestCollection.new(files)
26
+ if @tests.present?
27
+ test_runner.run_files(tests)
28
+ else
29
+ shell.notify "Could not find matching test file."
30
+ end
31
+ end
32
+
33
+ def status
34
+ files = repo.status_files.map {|f| {:file => f} }
35
+ @tests = TestCollection.new(files)
36
+
37
+ if tests.include_selenium?
38
+ handle_selenium
39
+ end
40
+
41
+ if tests.empty?
42
+ shell.notify 'No tests to run'
43
+ exit
44
+ end
45
+
46
+ test_runner.run_files(tests)
47
+ end
48
+
49
+ private
50
+
51
+ def handle_selenium
52
+ if ignore_selenium || shell.deny?("The status includes some selenium files. Do you wish to run those?")
53
+ tests.remove_selenium!
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'test_runner'
2
+ require_relative 'shell_runner'
3
+
4
+ class TestMethodRunner
5
+
6
+ def self.run(regex, env)
7
+ new(env).run(regex)
8
+ end
9
+
10
+ attr_reader :regex, :repo, :shell, :test_runner
11
+ def initialize(env)
12
+ @repo = env[:repo]
13
+ @shell = env[:shell]
14
+ @test_runner = env[:test_runner]
15
+ end
16
+
17
+ def run(regex)
18
+ @regex = regex
19
+
20
+ if tests.empty?
21
+ shell.notify "Could not find matching test method."
22
+ return false
23
+ elsif tests.size == 1
24
+ test_runner.run_method(tests.first)
25
+ elsif tests.in_one_file?
26
+ shell.notify "Multiple matches in same file. Running that file."
27
+ test_runner.run_files(tests)
28
+ elsif tests.in_one_engine? && tests.full_paths.size < 4 # hack: maybe should ask here?
29
+ shell.notify "Multiple matches across files in same engine. Running those files."
30
+ test_runner.run_files(tests)
31
+ else
32
+ shell.warn 'Found too many tests:'
33
+ tests[0..10].each {|t| shell.notify "#{t.full_path}: #{t.test_name}" }
34
+ shell.notify '...'
35
+ exit
36
+ end
37
+ end
38
+
39
+ def tests
40
+ @test_collection ||= TestCollection.new(find_tests_by_name)
41
+ end
42
+
43
+ def find_tests_by_name
44
+ test_def_regex = "^\s*def .*#{regex}.*"
45
+ begin
46
+ return repo.grep(test_def_regex, file_pattern: '*_test.rb')
47
+ rescue ShellRunner::CommandFailureError
48
+ # git grep exits with 1 if no results
49
+ return []
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,78 @@
1
+ require_relative 'shell_runner'
2
+
3
+ class TestRunner
4
+
5
+ attr_reader :shell, :all_engines_param
6
+ def initialize(env)
7
+ @shell = env[:shell]
8
+ @all_engines_param = env[:all_engines]
9
+ end
10
+
11
+ def run_method(test)
12
+ test_runner = named_test_runner(test.working_dir)
13
+
14
+ shell.exec("#{test_runner} #{test.relative_path} --name=#{test.test_name}", dir: test.working_dir)
15
+ end
16
+
17
+ def run_files(tests)
18
+ begin
19
+ test_runner = test_collection_runner(tests.working_dir)
20
+ test_files = tests.relative_paths.join(' ')
21
+
22
+ shell.exec("#{test_runner} #{test_files}", dir: tests.working_dir)
23
+ rescue TestCollection::MultipleWorkingDirectoriesError => e
24
+ if run_across_engines?
25
+ run_across_engines(tests)
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def run_across_engines(tests)
33
+ shell.notify "\nfinding test runners"
34
+ tests.working_dirs.each do |engine_dir|
35
+ test_files = tests.relative_paths_in(engine_dir).join(' ')
36
+ test_runner = test_collection_runner(engine_dir)
37
+
38
+ shell.enqueue("#{test_runner} #{test_files}", dir: engine_dir)
39
+ end
40
+ shell.exec_queue
41
+ end
42
+
43
+ def test_runner_type(working_dir)
44
+ if shell.run("ls bin", dir: working_dir).split("\n").include? 'testunit'
45
+ :spring
46
+ else
47
+ :ruby
48
+ end
49
+ rescue ShellRunner::CommandFailureError
50
+ :ruby
51
+ end
52
+
53
+ def named_test_runner(working_dir)
54
+ if test_runner_type(working_dir) == :spring
55
+ # hack:
56
+ # Add some options for using spring.
57
+ #
58
+ #"bin/testunit"
59
+ "ruby -I test"
60
+ else
61
+ "ruby -I test"
62
+ end
63
+ end
64
+
65
+ def test_collection_runner(working_dir)
66
+ if test_runner_type(working_dir) == :spring
67
+ #"bin/testunit"
68
+ %{ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + "/" + file) }'}
69
+ else
70
+ %{ruby -I test -e 'ARGV.each { |file| require(Dir.pwd + "/" + file) }'}
71
+ end
72
+ end
73
+
74
+ def run_across_engines?
75
+ all_engines_param || shell.confirm?("Test files are in multiple engines. Run them all?")
76
+ end
77
+
78
+ end
data/lib/tester.rb ADDED
@@ -0,0 +1,70 @@
1
+ require_relative 'needs_manager'
2
+ require_relative 'test_collection'
3
+ require_relative 'test_method_runner'
4
+ require_relative 'test_file_runner'
5
+ require_relative 'status_checker'
6
+
7
+ require 'rubygems'
8
+ require 'pry'
9
+
10
+ class Tester
11
+
12
+ def self.needs
13
+ [:shell, :repo, :test_runner]
14
+ end
15
+
16
+ def self.find(inputs, options)
17
+ env = NeedsManager.configure(:test_runner, needs, options.merge(repo_type: :info))
18
+ new(env).find(inputs)
19
+ end
20
+
21
+ def self.status(options)
22
+ env = NeedsManager.configure(:test_runner, needs, options.merge(repo_type: :info))
23
+ new(env).status(options)
24
+ end
25
+
26
+ def self.status_check(options)
27
+ env = NeedsManager.configure(:test_runner, (needs - [:test_runner]), options.merge(repo_type: :info))
28
+ new(env).status_check(options)
29
+ end
30
+
31
+ attr_accessor :env
32
+ def initialize(env)
33
+ @env = env
34
+ end
35
+
36
+ def find(inputs)
37
+ # each of these replaces this process if successful
38
+ # so no need for logic control flow
39
+ if query_might_be_method?(inputs)
40
+ TestMethodRunner.run(inputs.first, env)
41
+ end
42
+ TestFileRunner.find(inputs, env)
43
+ env[:shell].warn "Giving up :("
44
+ end
45
+
46
+ def status(options)
47
+ TestFileRunner.status(env, options[:no_selenium])
48
+ end
49
+
50
+ def status_check(options)
51
+ StatusChecker.report(env, options[:confirm_exit_status])
52
+ end
53
+
54
+ private
55
+
56
+ def query_might_be_method?(inputs)
57
+ if inputs.any? {|input| is_file_path?(input) }
58
+ false
59
+ elsif inputs.size > 1
60
+ false
61
+ else
62
+ true
63
+ end
64
+ end
65
+
66
+ def is_file_path?(input)
67
+ !! input.match(/\.rb/)
68
+ end
69
+
70
+ end
data/lib/upper.rb ADDED
@@ -0,0 +1,72 @@
1
+ require_relative 'needs_manager'
2
+ require_relative 'hook_manager'
3
+ require_relative 'pre_push_hook'
4
+
5
+ require 'rubygems'
6
+ require 'pry'
7
+
8
+ class Upper
9
+
10
+ def self.needs
11
+ [:shell, :repo, :bundler, :migrator]
12
+ end
13
+
14
+ def self.rebase_on_master!(options)
15
+ env = NeedsManager.configure(:up, needs, options.merge(repo_type: :active))
16
+ new(env).rebase_on_master!
17
+ end
18
+
19
+ def self.up_master!(options)
20
+ env = NeedsManager.configure(:up, needs, options.merge(repo_type: :active))
21
+ new(env).up_master!
22
+ end
23
+
24
+ def self.no_git(options)
25
+ env = NeedsManager.configure(:up, needs, options.merge(repo_type: :lazy))
26
+ new(env).no_git
27
+ end
28
+
29
+ def self.install_hooks(options)
30
+ env = NeedsManager.configure(:up, needs, options.merge(repo_type: :lazy))
31
+ new(env).install_hooks
32
+ end
33
+
34
+ def self.pre_push_hook(git_command, options)
35
+ env = NeedsManager.configure(:up, needs, options.merge(repo_type: :lazy))
36
+ new(env).pre_push_hook(git_command)
37
+ end
38
+
39
+ attr_reader :env, :repo, :bundler, :migrator
40
+
41
+ def initialize(env)
42
+ @env = env
43
+ @repo = env[:repo]
44
+ @bundler = env[:bundler]
45
+ @migrator = env[:migrator]
46
+ end
47
+
48
+ def up_master!
49
+ repo.up_master!
50
+ bundler.bundle_where_necessary
51
+ migrator.migrate_where_necessary
52
+ end
53
+
54
+ def rebase_on_master!
55
+ repo.rebase_on_master!
56
+ bundler.bundle_where_necessary
57
+ migrator.migrate_where_necessary
58
+ end
59
+
60
+ def no_git
61
+ bundler.bundle_where_necessary
62
+ migrator.migrate_where_necessary
63
+ end
64
+
65
+ def install_hooks
66
+ HookManager.install!(env)
67
+ end
68
+
69
+ def pre_push_hook(git_command)
70
+ PrePushHook.check(git_command, env)
71
+ end
72
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sfb_scripts
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pete Kinnecom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: '1.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0.19'
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ description: Easily update your rails app and run tests from command line
34
+ email:
35
+ - pete.kinnecom@gmail.com
36
+ executables:
37
+ - test_runner
38
+ - app_up
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - lib/active_repo.rb
43
+ - lib/bundle_manager.rb
44
+ - lib/hook_manager.rb
45
+ - lib/lazy_repo.rb
46
+ - lib/loud_shell_runner.rb
47
+ - lib/migrator.rb
48
+ - lib/needs_manager.rb
49
+ - lib/pre_push_hook.rb
50
+ - lib/repo.rb
51
+ - lib/shell_runner.rb
52
+ - lib/status_checker.rb
53
+ - lib/string_extension.rb
54
+ - lib/test_case.rb
55
+ - lib/test_collection.rb
56
+ - lib/test_file_runner.rb
57
+ - lib/test_method_runner.rb
58
+ - lib/test_runner.rb
59
+ - lib/tester.rb
60
+ - lib/upper.rb
61
+ - bin/test_runner
62
+ - bin/app_up
63
+ homepage: http://github.com/petekinnecom/dev_scripts/
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.1.11
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Easily update your rails app and run tests from command line
87
+ test_files: []
88
+ has_rdoc: