ora-dev-tools 1.2.1
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/.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
|
+
|