sfb_scripts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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: