ora-dev-tools 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +25 -0
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +5 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/devtools.gemspec +32 -0
- data/exe/jdiff +7 -0
- data/exe/prlist +43 -0
- data/exe/runtest +80 -0
- data/lib/devtools.rb +3 -0
- data/lib/devtools/options.rb +81 -0
- data/lib/devtools/utils.rb +8 -0
- data/lib/devtools/version.rb +4 -0
- data/lib/jira_diff.rb +43 -0
- data/lib/jira_diff/git.rb +30 -0
- data/lib/jira_diff/globals.rb +4 -0
- data/lib/jira_diff/options.rb +68 -0
- data/lib/jira_diff/stories.rb +122 -0
- data/lib/jira_diff/story.rb +53 -0
- data/lib/pr_list.rb +4 -0
- data/lib/pr_list/globals.rb +6 -0
- data/lib/pr_list/options.rb +55 -0
- data/lib/pr_list/pull_requests.rb +87 -0
- data/lib/runtest.rb +3 -0
- data/lib/runtest/globals.rb +4 -0
- data/lib/runtest/options.rb +100 -0
- metadata +179 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require "devtools"
|
2
|
+
|
3
|
+
module JIRADiff
|
4
|
+
class OptParse
|
5
|
+
|
6
|
+
def self.default_options
|
7
|
+
{
|
8
|
+
debug: false,
|
9
|
+
directory: ".",
|
10
|
+
dryrun: false,
|
11
|
+
master: "master",
|
12
|
+
source: [],
|
13
|
+
verbose: true
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(argv_opts = [], unit_testing = false)
|
18
|
+
opt_parse = DevTools::OptParse.new({ name: PROGRAM_NAME,
|
19
|
+
version: VERSION,
|
20
|
+
testing: unit_testing,
|
21
|
+
defaults: default_options })
|
22
|
+
|
23
|
+
parser = opt_parse.parser
|
24
|
+
|
25
|
+
parser.banner = "Usage: #{DevTools::PROGRAM} [OPTIONS]"
|
26
|
+
|
27
|
+
parser.separator ""
|
28
|
+
parser.separator "[OPTIONS]"
|
29
|
+
|
30
|
+
parser.separator ""
|
31
|
+
parser.separator "Specific Options:"
|
32
|
+
|
33
|
+
parser.on("-d", "--directory DIR", "Use DIR as our source directory") do |dir|
|
34
|
+
dir = File.expand_path(dir.strip)
|
35
|
+
if Dir.exist?(dir)
|
36
|
+
Options.directory = dir
|
37
|
+
else
|
38
|
+
raise ArgumentError, "ENOEXIST: Directory does not exist -> #{dir}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
parser.on("-m", "--master BRANCH", "Specify a master branch (default: master)") { |m| Options.master = m }
|
43
|
+
parser.on("-s", "--source BRANCH",
|
44
|
+
"Use BRANCH as the source to compare against (may be used more than once)") do |branch|
|
45
|
+
Options.source << branch unless Options.source.include?(branch)
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.separator ""
|
49
|
+
parser.separator "Common Options:"
|
50
|
+
|
51
|
+
parser.parse!(argv_opts)
|
52
|
+
|
53
|
+
validate_options(Options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.validate_options(opts)
|
57
|
+
if opts.source.include?(opts.master)
|
58
|
+
raise RuntimeError, "Source branches cannot include the master branch"
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.source = ["develop"] if opts.source.empty?
|
62
|
+
opts.master = "master" if opts.master.nil? || opts.master.strip == ""
|
63
|
+
|
64
|
+
opts
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'jira_diff/story'
|
2
|
+
require 'jira_diff/git'
|
3
|
+
|
4
|
+
module JIRADiff
|
5
|
+
class Stories
|
6
|
+
|
7
|
+
def initialize(opts = Options.defaults)
|
8
|
+
@branches = _get_branches(opts[:master], opts[:source])
|
9
|
+
@directory = opts[:directory] || '.'
|
10
|
+
@includes = _get_includes(opts.includes)
|
11
|
+
@options = opts
|
12
|
+
@stories = opts[:stories] || {}
|
13
|
+
|
14
|
+
_get_stories if @stories == {}
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :branches, :directory
|
18
|
+
attr_reader :stories, :includes
|
19
|
+
|
20
|
+
alias dir directory
|
21
|
+
|
22
|
+
def each
|
23
|
+
@stories.values.each do |stories|
|
24
|
+
stories.each { |story| yield story }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def source
|
29
|
+
@branches[1, @branches.size]
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_include(story)
|
33
|
+
@includes << story
|
34
|
+
end
|
35
|
+
|
36
|
+
def includes=(file)
|
37
|
+
@includes = _get_includes(file)
|
38
|
+
end
|
39
|
+
|
40
|
+
def master
|
41
|
+
@branches[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def master=(new_master)
|
45
|
+
@stories[master] = []
|
46
|
+
@branches[0] = new_master
|
47
|
+
_get_stories(new_master)
|
48
|
+
end
|
49
|
+
|
50
|
+
def shas
|
51
|
+
source.map do |branch|
|
52
|
+
stories[branch].map { |s| s.sha }
|
53
|
+
end.flatten.reverse
|
54
|
+
end
|
55
|
+
|
56
|
+
def source_stories
|
57
|
+
story_index = {}
|
58
|
+
|
59
|
+
source.each do |branch|
|
60
|
+
stories[branch].each { |s| story_index[s.sha] = s }
|
61
|
+
end
|
62
|
+
|
63
|
+
story_index.values
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_story(branch, story)
|
67
|
+
(@stories[branch] ||= []).push story
|
68
|
+
end
|
69
|
+
|
70
|
+
def find(branch, sha)
|
71
|
+
raise ArgumentError, "Invalid environment #{branch}" unless @branches.include?(branch)
|
72
|
+
|
73
|
+
@stories[branch].each { |story| return true if story.sha == sha }
|
74
|
+
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def diff
|
79
|
+
stories = []
|
80
|
+
opts = @options
|
81
|
+
|
82
|
+
source_stories.each do |story|
|
83
|
+
stories << story unless find(master, story.sha)
|
84
|
+
end
|
85
|
+
|
86
|
+
opts.source = ['diff']
|
87
|
+
opts.stories = {'diff' => stories.flatten}
|
88
|
+
Stories.new opts
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def _get_branches(master, sources)
|
94
|
+
branches = [] << (master.nil? ? 'master' : master)
|
95
|
+
branches << (sources.empty? ? ['develop'] : sources)
|
96
|
+
branches.flatten
|
97
|
+
end
|
98
|
+
|
99
|
+
def _get_includes(includes_file)
|
100
|
+
lines = []
|
101
|
+
if includes_file && File.exist?(includes_file)
|
102
|
+
File.open(includes_file, 'r') do |f|
|
103
|
+
f.each_line { |line| lines << $1 if line =~ /(\w+\-\d+)/ }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
lines
|
107
|
+
end
|
108
|
+
|
109
|
+
def _get_stories(branches = @branches)
|
110
|
+
git = Git.new(@directory)
|
111
|
+
|
112
|
+
branches.to_a.each do |branch|
|
113
|
+
puts "checking #{branch}" if @options.debug
|
114
|
+
git.log(branch).each do |line|
|
115
|
+
add_story branch, Story.new(line)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module JIRADiff
|
2
|
+
|
3
|
+
class Story
|
4
|
+
def initialize( story )
|
5
|
+
unless story =~ /\S+|\S+/
|
6
|
+
raise ArgumentError, "story must follow 'SHA|description' format"
|
7
|
+
end
|
8
|
+
|
9
|
+
@sha, @description = story.split('|')
|
10
|
+
|
11
|
+
raise ArgumentError if @sha.nil? || @description.nil?
|
12
|
+
end
|
13
|
+
attr_reader :sha
|
14
|
+
|
15
|
+
def split_story( description = @description )
|
16
|
+
raise RuntimeError 'description cannot be blank' unless description
|
17
|
+
|
18
|
+
stories = []
|
19
|
+
story_pattern = /\[?(((SRMPRT|OSMCLOUD)\-\d+)|NO-JIRA)\]?[,:\-\s]+\s*(.*)$/
|
20
|
+
line = description.match(story_pattern)
|
21
|
+
|
22
|
+
if line.nil? # did not find a JIRA ticket pattern
|
23
|
+
stories.push 'NO-JIRA'
|
24
|
+
desc = description.strip
|
25
|
+
else
|
26
|
+
stories.push line.captures[0]
|
27
|
+
desc = line.captures[3].strip
|
28
|
+
end
|
29
|
+
|
30
|
+
# Perform recursion if there are multiple tickets in the description
|
31
|
+
if desc =~ story_pattern
|
32
|
+
new_story, new_desc = split_story desc
|
33
|
+
stories.push new_story
|
34
|
+
desc = new_desc
|
35
|
+
end
|
36
|
+
|
37
|
+
[stories.flatten, desc]
|
38
|
+
end
|
39
|
+
|
40
|
+
def tickets
|
41
|
+
(split_story)[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def desc
|
45
|
+
(split_story)[1]
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
'[%07.07s] %s - %s' % [sha, tickets.join(', '), desc]
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/pr_list.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
module DevTools
|
3
|
+
module PRlist
|
4
|
+
class OptParse
|
5
|
+
|
6
|
+
def self.default_options
|
7
|
+
{
|
8
|
+
markdown: false,
|
9
|
+
queue: false
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.validate_options
|
14
|
+
raise RuntimeError, "Missing configuration file" if Options.nil?
|
15
|
+
raise RuntimeError, "Missing authentication token" if Options.token.nil?
|
16
|
+
raise RuntimeError, "No repositories provided" if Options.repos.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.parse(argv_opts = [], unit_testing = false)
|
20
|
+
opt_parse = DevTools::OptParse.new({ name: IDENT,
|
21
|
+
version: VERSION,
|
22
|
+
defaults: default_options,
|
23
|
+
testing: unit_testing })
|
24
|
+
|
25
|
+
parser = opt_parse.parser
|
26
|
+
|
27
|
+
parser.banner = "Usage: #{DevTools::PROGRAM} [OPTIONS]"
|
28
|
+
|
29
|
+
parser.separator ""
|
30
|
+
parser.separator "[OPTIONS]"
|
31
|
+
|
32
|
+
parser.on "-m", "--markdown", "Outputs in markdown friendly format" do
|
33
|
+
Options.markdown = true
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.on "--[no-]queue", "filters PRs into a queue list for QA (default)" do |opt|
|
37
|
+
Options.queue = opt
|
38
|
+
end
|
39
|
+
|
40
|
+
parser.separator ""
|
41
|
+
parser.separator "Common Options:"
|
42
|
+
|
43
|
+
parser.parse!(argv_opts)
|
44
|
+
|
45
|
+
validate_options unless unit_testing
|
46
|
+
|
47
|
+
Options
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.label_values
|
51
|
+
Options.labels.keys.map { |k| Options.labels[k] }.flatten.compact
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "octokit"
|
2
|
+
|
3
|
+
module DevTools
|
4
|
+
module PRlist
|
5
|
+
class PullRequest
|
6
|
+
attr_reader :issue
|
7
|
+
|
8
|
+
def method_missing(method_sym, *arguments, &block)
|
9
|
+
@issue.respond_to?(method_sym) ? @issue.send(method_sym, *arguments, &block) : super
|
10
|
+
end
|
11
|
+
|
12
|
+
def respond_to_missing?(method_name, include_private = false)
|
13
|
+
@issue.respond_to?(method_name.to_sym) || super
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(issue)
|
17
|
+
@issue ||= issue
|
18
|
+
end
|
19
|
+
|
20
|
+
def date
|
21
|
+
@issue.created_at
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_label?(filter_by)
|
25
|
+
labels.any? { |label| [filter_by].flatten.map{ |l| l.downcase.strip }.include?(label.downcase.strip) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def labels
|
29
|
+
@issue.labels.map { |l| l.name }
|
30
|
+
end
|
31
|
+
|
32
|
+
def repo(opt = {})
|
33
|
+
opt[:short] = false unless opt.has_key?(:short)
|
34
|
+
|
35
|
+
/repos\/(\w*\/?(.*))$/.match(@issue.repository_url)[opt[:short] ? 2 : 1]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class PullRequests
|
40
|
+
attr_reader :pulls
|
41
|
+
|
42
|
+
def initialize(token = nil, repos = [])
|
43
|
+
@pulls ||= []
|
44
|
+
@github ||= __authenticate token
|
45
|
+
|
46
|
+
repos.each { |repo| load!(repo) } if authorized?
|
47
|
+
end
|
48
|
+
|
49
|
+
def authorized?
|
50
|
+
return !@github.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
def auth!(token)
|
54
|
+
@github = __authenticate token
|
55
|
+
end
|
56
|
+
|
57
|
+
def load!(repo)
|
58
|
+
raise NoAuthError, "You must authorized with github using #auth first" unless authorized?
|
59
|
+
|
60
|
+
@github.issues(repo).each do |issue|
|
61
|
+
__load_issue issue if issue.pull_request?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def by_date
|
66
|
+
sorted_pulls = @pulls.sort_by { |pr| pr.date }
|
67
|
+
|
68
|
+
block_given? ? sorted_pulls.each { |pr| yield pr } : sorted_pulls
|
69
|
+
end
|
70
|
+
|
71
|
+
def repos
|
72
|
+
@pulls.collect { |pr| pr.repo }.uniq
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def __load_issue(issue)
|
78
|
+
@pulls.push PullRequest.new issue
|
79
|
+
end
|
80
|
+
|
81
|
+
def __authenticate(token)
|
82
|
+
token ? Octokit::Client.new(access_token: token) : nil
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/runtest.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module RunTest
|
2
|
+
class OptParse
|
3
|
+
def self.default_options
|
4
|
+
{
|
5
|
+
basedir: "src/js",
|
6
|
+
changed: false,
|
7
|
+
commands: Config::Options.new,
|
8
|
+
jest: true,
|
9
|
+
mocha: true,
|
10
|
+
verbose: 0
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Return a structure describing the Options.
|
16
|
+
#
|
17
|
+
def self.parse(args, unit_testing=false)
|
18
|
+
# The Options specified on the command line will be collected in *Options*.
|
19
|
+
# We set default values here.
|
20
|
+
opt_parse = DevTools::OptParse.new({ name: PROGRAM_NAME,
|
21
|
+
version: VERSION,
|
22
|
+
defaults: default_options,
|
23
|
+
testing: unit_testing })
|
24
|
+
|
25
|
+
opt_parse.default_options(Options.commands, {
|
26
|
+
diff: "git diff --name-only develop src/js | egrep \".js$\"",
|
27
|
+
jest: "$(npm bin)/jest",
|
28
|
+
jest_full: "npm run test:jest",
|
29
|
+
mocha: "$(npm bin)/mocha --require src/js/util/test-dom.js --compilers js:babel-core/register",
|
30
|
+
mocha_full: "npm run test:mocha"
|
31
|
+
})
|
32
|
+
|
33
|
+
parser = opt_parse.parser
|
34
|
+
|
35
|
+
parser.banner = "Usage: #{DevTools::PROGRAM} [OPTIONS] [PATTERN]"
|
36
|
+
parser.banner += "\n\nWhere [PATTERN] is any full or partial filename."
|
37
|
+
parser.banner += " All tests matching this filename pattern will be run."
|
38
|
+
|
39
|
+
parser.separator ""
|
40
|
+
parser.separator "[OPTIONS]"
|
41
|
+
|
42
|
+
parser.separator ""
|
43
|
+
parser.separator "Specific Options:"
|
44
|
+
|
45
|
+
# Base directory
|
46
|
+
parser.on("-b", "--basedir DIR", "Specify the base directory to search for tests (DEFAULT: '#{Options.basedir}')") do |dir|
|
47
|
+
Options.basedir = dir
|
48
|
+
end
|
49
|
+
|
50
|
+
# Changed switch
|
51
|
+
parser.on("-c", "--changed", "Run specs for any files that have recently been modified") do
|
52
|
+
Options.changed = true
|
53
|
+
end
|
54
|
+
|
55
|
+
parser.separator ""
|
56
|
+
parser.separator "Test Runners:"
|
57
|
+
|
58
|
+
parser.on("-j", "--[no-]jest", "Only/Don't run Jest tests") do |jest|
|
59
|
+
Options.jest = true; Options.mocha = false
|
60
|
+
(Options.jest = false; Options.mocha = true) unless jest
|
61
|
+
end
|
62
|
+
|
63
|
+
parser.on("-m", "--[no-]mocha", "Only/Don't run Mocha tests") do |mocha|
|
64
|
+
Options.jest = false; Options.mocha = true
|
65
|
+
(Options.jest = true; Options.mocha = false) unless mocha
|
66
|
+
end
|
67
|
+
|
68
|
+
parser.separator ""
|
69
|
+
parser.separator "Test Commands:"
|
70
|
+
|
71
|
+
parser.on("--diff-cmd CMD", "Overwrite git diff command: '#{Options.commands.diff}'") do |cmd|
|
72
|
+
Options.commands.diff = cmd
|
73
|
+
end
|
74
|
+
|
75
|
+
parser.on("--jest-cmd CMD", "Overwrite Jest command: '#{Options.commands.jest}'") do |cmd|
|
76
|
+
Options.commands.jest = cmd
|
77
|
+
end
|
78
|
+
|
79
|
+
parser.on("--jest-full-cmd CMD", "Overwrite Jest full-suite command: '#{Options.commands.jest_full}'") do |cmd|
|
80
|
+
Options.commands.jest_full = cmd
|
81
|
+
end
|
82
|
+
|
83
|
+
parser.on("--mocha-cmd CMD", "Overwrite Mocha command: '#{Options.commands.mocha}'") do |cmd|
|
84
|
+
Options.commands.mocha = cmd
|
85
|
+
end
|
86
|
+
|
87
|
+
parser.on("--mocha-full-cmd CMD", "Overwrite Mocha command: '#{Options.commands.mocha_full}'") do |cmd|
|
88
|
+
Options.commands.mocha_full = cmd
|
89
|
+
end
|
90
|
+
|
91
|
+
parser.separator ""
|
92
|
+
parser.separator "Common Options:"
|
93
|
+
|
94
|
+
parser.parse!(args)
|
95
|
+
|
96
|
+
return Options
|
97
|
+
end
|
98
|
+
end # class OptParse
|
99
|
+
end # module RunTest
|
100
|
+
|