specss 1.0.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
+ SHA256:
3
+ metadata.gz: 62e0dda02c8ae2b19b17707496db1b5074ffdd0cb592ace3ca41e09b715f52e3
4
+ data.tar.gz: acce2bed54b8bde82ba941ea4e968633c53237fce1345731bd09ba86b58a5e40
5
+ SHA512:
6
+ metadata.gz: e71febd9e68f475df1d9e46bccddbc813b21e8d6c8824d6f30cdaa2a72938253e50f498b9f6be2d37e5798618487578eeb302ea25b878d253601c41c88c54db1
7
+ data.tar.gz: a6b638d032f2bd789e4b94a4efb75a65c52702ae99dd41e7a930ac502112ca12c769cd4addd00dd529843ef920f13997990f95b9eacc7e1282cd84539d2176b9
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .DS_STORE
2
+ Gemfile.lock
3
+ /builds
4
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gemspec
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Smarter Rspec Runner
2
+ Script that runs specs for Spectra Rails projects based off of dependencies and perforce changelists
3
+
4
+ ### Gathering Dependents
5
+ In the script I utilize the [Rubrowser](https://github.com/emad-elsaid/rubrowser) gem to create a dependency graph for the code.
6
+
7
+ ### Installation
8
+ This gem is publicly available on RubyGems.
9
+ ```
10
+ gem install specss
11
+ ```
12
+ If your projects use different Ruby versions, then each one will require this step in order to run.
13
+
14
+ ### Use
15
+ Navigate to the root of your rails app or ruby project and simply run:
16
+
17
+ ```
18
+ specss
19
+ ```
20
+
21
+ By default, it only runs the 'lite' version that executes specs based on your p4 status. To run specs on all changed files and
22
+ all dependents of those changed files, run:
23
+
24
+ ```
25
+ specss -e
26
+ ```
27
+
28
+ For other information, print the help after running the executable:
29
+
30
+ ```
31
+ [~]$ specss -h
32
+ Usage: specss [option]
33
+ -e, --extended Run specs of modified files and dependents
34
+ -l, --lite Run specs of modified files only
35
+ -v, --version Smarter Specs Version
36
+ -h, --help Prints this help
37
+ ```
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ # Auto load gem into ruby console
9
+ task :console do
10
+ exec "irb -r specss -I ./lib"
11
+ end
12
+
13
+
data/bin/specss ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'specss'
5
+ require 'specss/executor'
6
+
7
+ ARGV << '-l' if ARGV.empty? # Default to lite if no arguments are passed
8
+
9
+ Options = Struct.new(:name)
10
+
11
+ ##
12
+ # Parse arguments that are passed when running specs
13
+ class Parser
14
+ def self.parse(options)
15
+
16
+ opt_parser = OptionParser.new do |opts|
17
+ opts.banner = "Usage: specss [option]"
18
+
19
+ opts.on("-e", "--extended", "Run specs of modified files and dependents") do |n|
20
+ Executor.main('extended')
21
+ end
22
+
23
+ opts.on("-l", "--lite", "Run specs of modified files only") do |n|
24
+ Executor.main('lite')
25
+ end
26
+
27
+ opts.on("-v", "--version", "Smarter Specs Version") do |n|
28
+ puts "Specss #{Specss::VERSION}"
29
+ end
30
+
31
+ opts.on("-h", "--help", "Prints this help") do
32
+ puts opts
33
+ exit
34
+ end
35
+ end
36
+
37
+ opt_parser.parse!(options)
38
+ end
39
+ end
40
+
41
+ begin
42
+ Parser.parse(ARGV)
43
+ rescue OptionParser::InvalidOption
44
+ puts "Warning: Invalid option"
45
+ exec("specss -h")
46
+ end
@@ -0,0 +1,63 @@
1
+ require 'specss/files'
2
+
3
+ module Executor
4
+ class << self
5
+
6
+ ##
7
+ # Takes in option from parse and executes main functions
8
+ def main(opt)
9
+ $changed_files = Files::Perforce.get_changelist_files
10
+
11
+ # Pass in options from ARGV on whether to run lite or extended
12
+ case opt
13
+ when 'extended'
14
+ specs_to_run = extended
15
+ else
16
+ specs_to_run = lite
17
+ end
18
+
19
+ if specs_to_run.empty?
20
+ puts 'No specs need to be run'
21
+ else
22
+ spec_names = Files::Specs.chop_file_paths(specs_to_run)
23
+ puts 'Running specs: ' + spec_names.join(" ")
24
+ exec "bundle exec rspec " + specs_to_run.join(" ")
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Returns all unique files in changelist and their dependents
30
+ def get_all_affected_files
31
+ all_files = $changed_files
32
+ dependents = get_dependents
33
+
34
+ dependents.each do |d|
35
+ all_files.push(d) unless all_files.include? d
36
+ end
37
+ all_files
38
+ end
39
+
40
+ ##
41
+ # Returns all dependents of files in changelist
42
+ def get_dependents
43
+ dependents = []
44
+ $changed_files.each do |f|
45
+ dependents_array = Files::Dependencies.get_dependencies(f)
46
+ dependents_array.each do |d|
47
+ dependents.push(d) unless dependents.include? d
48
+ end
49
+ end
50
+ dependents
51
+ end
52
+
53
+ def extended
54
+ all_files = get_all_affected_files
55
+ Files::Specs.get_specs(all_files)
56
+ end
57
+
58
+ def lite
59
+ Files::Specs.get_specs($changed_files)
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,81 @@
1
+ module Files
2
+ require 'json'
3
+
4
+ module Perforce
5
+ ##
6
+ # Returns all ruby files in changelist as an array of files without extension
7
+ def self.get_changelist_files
8
+ changed_files = []
9
+ p4_status = %x|p4 status &|
10
+ p4_array = p4_status.split("\n")
11
+
12
+ # Add all ruby files ready to be submitted to changed file array
13
+ p4_array.each do |p|
14
+ next unless p.include?('.rb')
15
+ file = p.split(' - ')[0]
16
+ status = p.split(' - ')[1]
17
+ changed_files.push(File.basename(file, ".*")) if status.include? 'submit'
18
+ end
19
+ changed_files
20
+ end
21
+ end
22
+
23
+ module Dependencies
24
+ ##
25
+ # Takes in a file and returns all files that are dependents as an array of files without extension
26
+ def self.get_dependencies(file)
27
+ dependents = []
28
+ # Get file name without extension and convert to camel case
29
+ basename = File.basename(file, ".*")
30
+ basename = basename.gsub(/(?:^|_)([a-z])/) do $1.upcase end
31
+
32
+ # Get rubrowser output and parse for the relation data
33
+ output = %x|rubrowser &|
34
+ data = output.match(/var\s+data\s+=\s+(.*?);/m)[1].split('</script>')[0]
35
+ data_hash = JSON.parse(data)
36
+ relations = data_hash['relations']
37
+
38
+ # Return dependents of input file
39
+ dependents_data = relations.select { |i| i['resolved_namespace'] == basename }
40
+ dependents_data.each do |d|
41
+ filename = d['file']
42
+ basename = File.basename(filename, ".*")
43
+ next if basename.include? '_spec'
44
+ dependents.push(basename) unless dependents.include? basename
45
+ end
46
+ dependents
47
+ end
48
+ end
49
+
50
+ module Specs
51
+ ##
52
+ # Returns all specs to run as an array of file paths relative to root
53
+ def self.get_specs(changed_files)
54
+ specs_to_run = []
55
+ specs = Dir.glob('spec/**/*').select{ |e| File.file? e }
56
+
57
+ # Check if each spec is included in the list of changed files
58
+ specs.each do |s|
59
+ spec_name = File.basename(s, ".*")
60
+ spec_name.slice! '_spec' if spec_name.include? '_spec'
61
+ next if spec_name.include? 'shared_examples'
62
+ specs_to_run.push(s) if changed_files.include? spec_name
63
+ end
64
+ specs_to_run
65
+ end
66
+
67
+ ##
68
+ # Returns array of specs to run with the absolute path chopped off
69
+ def self.chop_file_paths(specs)
70
+ specs_to_run = []
71
+
72
+ specs.each do |s|
73
+ spec_name = File.basename(s)
74
+ specs_to_run.push(spec_name)
75
+ end
76
+ specs_to_run
77
+ end
78
+ end
79
+
80
+ end
81
+
@@ -0,0 +1,3 @@
1
+ module Specss
2
+ VERSION = '1.0.0'
3
+ end
data/lib/specss.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'specss/version'
2
+ require 'specss/executor'
3
+
4
+ module Specss
5
+ end
data/specss.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'specss/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'specss'
7
+ s.version = Specss::VERSION
8
+ s.authors = ['Tom Bonan']
9
+ s.email = ['tombonan@spectralogic.com']
10
+ s.homepage = 'https://github.com/tombonan/smarter-specs'
11
+ s.summary = 'A smarter Rspec Runner'
12
+ s.description = 'A smarter Rspec Runner'
13
+ s.license = 'MIT'
14
+
15
+ s.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+
19
+ s.bindir = 'bin'
20
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ s.require_paths = ['lib']
22
+
23
+ s.add_runtime_dependency 'rubrowser', '~> 2.0.0'
24
+
25
+ s.post_install_message = "Welcome to the Spec Party"
26
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: specss
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Bonan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubrowser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0
27
+ description: A smarter Rspec Runner
28
+ email:
29
+ - tombonan@spectralogic.com
30
+ executables:
31
+ - specss
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gitignore"
36
+ - Gemfile
37
+ - README.md
38
+ - Rakefile
39
+ - bin/specss
40
+ - lib/specss.rb
41
+ - lib/specss/executor.rb
42
+ - lib/specss/files.rb
43
+ - lib/specss/version.rb
44
+ - specss.gemspec
45
+ homepage: https://github.com/tombonan/smarter-specs
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
49
+ post_install_message: Welcome to the Spec Party
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.0.3
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: A smarter Rspec Runner
68
+ test_files: []