specss 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/README.md +37 -0
- data/Rakefile +13 -0
- data/bin/specss +46 -0
- data/lib/specss/executor.rb +63 -0
- data/lib/specss/files.rb +81 -0
- data/lib/specss/version.rb +3 -0
- data/lib/specss.rb +5 -0
- data/specss.gemspec +26 -0
- metadata +68 -0
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
data/Gemfile
ADDED
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
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
|
data/lib/specss/files.rb
ADDED
@@ -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
|
+
|
data/lib/specss.rb
ADDED
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: []
|