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 +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: []
|