openstudio_measure_tester 0.1.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 +25 -0
- data/.rspec +3 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +15 -0
- data/Gemfile +8 -0
- data/LICENSE.md +13 -0
- data/README.md +61 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dashboard/css/bootstrap-grid.css +2050 -0
- data/dashboard/css/bootstrap-grid.min.css +7 -0
- data/dashboard/css/bootstrap-reboot.css +330 -0
- data/dashboard/css/bootstrap.css +8975 -0
- data/dashboard/css/bootstrap.min.css +7 -0
- data/dashboard/css/dashboard.css +191 -0
- data/dashboard/index.html +558 -0
- data/dashboard/js/bootstrap.js +3894 -0
- data/dashboard/js/bootstrap.min.js +7 -0
- data/dashboard/js/jquery-3.3.1.min.js +2 -0
- data/lib/openstudio_measure_tester.rb +49 -0
- data/lib/openstudio_measure_tester/core_ext.rb +69 -0
- data/lib/openstudio_measure_tester/coverage.rb +174 -0
- data/lib/openstudio_measure_tester/dashboard.rb +33 -0
- data/lib/openstudio_measure_tester/minitest_result.rb +144 -0
- data/lib/openstudio_measure_tester/openstudio_style.rb +502 -0
- data/lib/openstudio_measure_tester/openstudio_testing_result.rb +167 -0
- data/lib/openstudio_measure_tester/rake_task.rb +258 -0
- data/lib/openstudio_measure_tester/rubocop_result.rb +213 -0
- data/lib/openstudio_measure_tester/templates/dashboard.html.erb +566 -0
- data/lib/openstudio_measure_tester/test_helper.rb +44 -0
- data/lib/openstudio_measure_tester/version.rb +31 -0
- data/openstudio_measure_tester.gemspec +35 -0
- metadata +230 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
5
|
+
# following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
8
|
+
# disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
11
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
12
|
+
#
|
13
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior written permission from the respective party.
|
15
|
+
#
|
16
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
|
17
|
+
# works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
|
18
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
21
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
|
23
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25
|
+
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
########################################################################################################################
|
28
|
+
|
29
|
+
module OpenStudioMeasureTester
|
30
|
+
class OpenStudioTestingResult
|
31
|
+
attr_reader :results
|
32
|
+
|
33
|
+
# Pass in the results_dir where all the results are stored
|
34
|
+
# @param results_dir [String]: Directory where the results are scattered. Typically the root dir or where rake was executed
|
35
|
+
# @param test_results_dir [String]: Where the final results are to be stored
|
36
|
+
def initialize(results_dir, test_results_dir)
|
37
|
+
@results_dir = results_dir
|
38
|
+
@test_results_dir = test_results_dir
|
39
|
+
@results = {}
|
40
|
+
|
41
|
+
# get the repository info
|
42
|
+
g = Git.open(Dir.pwd)
|
43
|
+
config = g.config
|
44
|
+
repo_name = config['remote.origin.url'].split('/')[1].split('.')[0]
|
45
|
+
current_branch = g.branch.name
|
46
|
+
@results['repo_name'] = repo_name
|
47
|
+
@results['current_branch'] = current_branch
|
48
|
+
# TODO add failsafe
|
49
|
+
|
50
|
+
# check if the results data already exist, and if so, then load the file now to keep the results
|
51
|
+
load_results
|
52
|
+
aggregate_results
|
53
|
+
end
|
54
|
+
|
55
|
+
def aggregate_results
|
56
|
+
# TODO: check if we need this check of directories
|
57
|
+
if @test_results_dir != @results_dir
|
58
|
+
# coverage
|
59
|
+
if Dir.exist? "#{@results_dir}/coverage"
|
60
|
+
FileUtils.rm_rf "#{@test_results_dir}/coverage" if Dir.exist? "#{@test_results_dir}/coverage"
|
61
|
+
FileUtils.mv "#{@results_dir}/coverage", "#{@test_results_dir}/."
|
62
|
+
|
63
|
+
cov = OpenStudioMeasureTester::Coverage.new("#{@test_results_dir}/coverage")
|
64
|
+
@results["coverage"] = cov.to_hash
|
65
|
+
end
|
66
|
+
|
67
|
+
# minitest
|
68
|
+
if Dir.exist?("#{@results_dir}/test/html_reports") || Dir.exist?("#{@results_dir}/test/reports")
|
69
|
+
FileUtils.rm_rf "#{@test_results_dir}/minitest" if Dir.exist? "#{@test_results_dir}/minitest"
|
70
|
+
FileUtils.mkdir_p "#{@test_results_dir}/minitest"
|
71
|
+
FileUtils.mv "#{@results_dir}/test/html_reports", "#{@test_results_dir}/minitest/html_reports"
|
72
|
+
FileUtils.mv "#{@results_dir}/test/reports", "#{@test_results_dir}/minitest/reports"
|
73
|
+
|
74
|
+
# Delete the test folder if it is empty
|
75
|
+
FileUtils.rm_rf "#{@results_dir}/test" if Dir.entries("#{@results_dir}/test").size == 2
|
76
|
+
|
77
|
+
# Load in the data into the minitest object
|
78
|
+
mr = OpenStudioMeasureTester::MinitestResult.new("#{@test_results_dir}/minitest")
|
79
|
+
@results['minitest'] = mr.summary
|
80
|
+
end
|
81
|
+
|
82
|
+
# rubocop
|
83
|
+
if Dir.exist? "#{@results_dir}/rubocop"
|
84
|
+
FileUtils.rm_rf "#{@test_results_dir}/rubocop" if Dir.exist? "#{@test_results_dir}/rubocop"
|
85
|
+
FileUtils.mv "#{@results_dir}/rubocop", "#{@test_results_dir}/rubocop"
|
86
|
+
|
87
|
+
# need to create parser here!
|
88
|
+
# trying!!! &^&%##%@((@*&()))!!
|
89
|
+
rc = OpenStudioMeasureTester::RubocopResult.new("#{@test_results_dir}/rubocop")
|
90
|
+
@results['rubocop'] = rc.summary
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
# openstudio style
|
95
|
+
if Dir.exist? "#{@results_dir}/openstudio_style"
|
96
|
+
FileUtils.rm_rf "#{@test_results_dir}/openstudio_style" if Dir.exist? "#{@test_results_dir}/openstudio_style"
|
97
|
+
FileUtils.mv "#{@results_dir}/openstudio_style", "#{@test_results_dir}/openstudio_style"
|
98
|
+
|
99
|
+
# OpenStudio Style will have already run, so just grab the results out of the directory and jam into
|
100
|
+
# the @results hash
|
101
|
+
filename = "#{@test_results_dir}/openstudio_style/openstudio_style.json"
|
102
|
+
if File.exist? filename
|
103
|
+
@results['openstudio_style'] = JSON.parse(File.read(filename))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def load_results
|
110
|
+
filename = "#{@test_results_dir}/combined_results.json"
|
111
|
+
begin
|
112
|
+
@results = JSON.parse(File.read(filename)) if File.exist? filename
|
113
|
+
rescue
|
114
|
+
@results = {}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def save_results
|
119
|
+
File.open("#{@test_results_dir}/combined_results.json", 'w') do |file|
|
120
|
+
file << JSON.pretty_generate(@results)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return the exit code based on some arbitrary limit across all the tests
|
125
|
+
def exit_code
|
126
|
+
# there must be no unit test failures
|
127
|
+
# pp @results
|
128
|
+
final_exit_code = 0
|
129
|
+
if @results['rubocop']
|
130
|
+
if @results['rubocop']['total_errors'] > 0
|
131
|
+
puts 'RuboCop errors found.'
|
132
|
+
final_exit_code = 1
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if @results['openstudio_style']
|
137
|
+
if @results['openstudio_style']['total_errors'] > 0
|
138
|
+
puts 'OpenStudio Style errors found.'
|
139
|
+
final_exit_code = 1
|
140
|
+
end
|
141
|
+
if @results['openstudio_style']['total_warnings'] > 10
|
142
|
+
puts 'More than 10 OpenStudio Style warnings found, reporting as error'
|
143
|
+
final_exit_code = 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if @results['minitest']
|
148
|
+
if @results['minitest']['total_errors'] > 0 || @results['minitest']['total_failures'] > 0
|
149
|
+
puts 'Unit Test (MiniTest) errors/failures found.'
|
150
|
+
final_exit_code = 1
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
if @results['coverage']
|
155
|
+
if @results['coverage']['total_percent_coverage'] < 70
|
156
|
+
puts 'Code coverage is less than 70%, raising error.'
|
157
|
+
final_exit_code = 1
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
puts 'Open ./test_results/dashboard/index.html to view measure testing dashboard.'
|
162
|
+
|
163
|
+
return final_exit_code
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
@@ -0,0 +1,258 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
5
|
+
# following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
8
|
+
# disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
11
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
12
|
+
#
|
13
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior written permission from the respective party.
|
15
|
+
#
|
16
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
|
17
|
+
# works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
|
18
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
21
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
|
23
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25
|
+
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
########################################################################################################################
|
28
|
+
|
29
|
+
require 'rake'
|
30
|
+
require 'rake/tasklib'
|
31
|
+
require 'rake/testtask'
|
32
|
+
require 'rubocop/rake_task'
|
33
|
+
|
34
|
+
require_relative '../openstudio_measure_tester'
|
35
|
+
|
36
|
+
module OpenStudioMeasureTester
|
37
|
+
class RakeTask < Rake::TaskLib
|
38
|
+
attr_accessor :name
|
39
|
+
|
40
|
+
def initialize(*args, &task_block)
|
41
|
+
@name = args.shift || :openstudio
|
42
|
+
|
43
|
+
setup_subtasks(@name)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Prepare the current directory and the root directory to remove old test results before running
|
49
|
+
# the new tests
|
50
|
+
def pre_process_minitest(base_dir)
|
51
|
+
current_dir = Dir.pwd
|
52
|
+
test_results_dir = "#{base_dir}/test_results"
|
53
|
+
|
54
|
+
puts "Current directory is #{current_dir}"
|
55
|
+
puts "Pre-processing tests run in #{base_dir}"
|
56
|
+
puts "Test results will be stored in: #{test_results_dir}"
|
57
|
+
|
58
|
+
FileUtils.rm_rf "#{test_results_dir}/coverage" if Dir.exist? "#{test_results_dir}/coverage"
|
59
|
+
FileUtils.rm_rf "#{test_results_dir}/test/html_reports" if Dir.exist? "#{test_results_dir}/test/html_reports"
|
60
|
+
FileUtils.rm_rf "#{test_results_dir}/test/reports" if Dir.exist? "#{test_results_dir}/test/reports"
|
61
|
+
# remove the test directory if it is empty (size == 2 for . and ..)
|
62
|
+
if Dir.exist?("#{test_results_dir}/test") && Dir.entries("#{test_results_dir}/test").size == 2
|
63
|
+
FileUtils.rm_rf "#{test_results_dir}/test"
|
64
|
+
end
|
65
|
+
FileUtils.rm_rf "#{test_results_dir}/minitest" if Dir.exist? "#{test_results_dir}/minitest"
|
66
|
+
FileUtils.rm_rf "#{base_dir}/coverage" if Dir.exist? "#{base_dir}/coverage"
|
67
|
+
FileUtils.rm_rf "#{base_dir}/test" if Dir.exist? "#{base_dir}/test"
|
68
|
+
FileUtils.rm_rf "#{base_dir}/minitest" if Dir.exist? "#{base_dir}/minitest"
|
69
|
+
FileUtils.rm_rf "#{current_dir}/coverage" if Dir.exist? "#{current_dir}/coverage"
|
70
|
+
FileUtils.rm_rf "#{current_dir}/test" if Dir.exist? "#{current_dir}/test"
|
71
|
+
FileUtils.rm_rf "#{current_dir}/minitest" if Dir.exist? "#{current_dir}/minitest"
|
72
|
+
|
73
|
+
# Create the test_results directory to store all the results
|
74
|
+
FileUtils.mkdir_p "#{base_dir}/test_results"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Rubocop stores the results (for now) in the test_results directory
|
78
|
+
def pre_process_rubocop(base_dir)
|
79
|
+
current_dir = Dir.pwd
|
80
|
+
test_results_dir = "#{base_dir}/test_results"
|
81
|
+
|
82
|
+
puts "Current directory is #{current_dir}"
|
83
|
+
puts "Pre-processing tests run in #{base_dir}"
|
84
|
+
puts "Test results will be stored in: #{test_results_dir}"
|
85
|
+
|
86
|
+
FileUtils.rm_rf "#{test_results_dir}/rubocop" if Dir.exist? "#{test_results_dir}/rubocop"
|
87
|
+
FileUtils.rm_rf "#{base_dir}/rubocop" if Dir.exist? "#{base_dir}/rubocop"
|
88
|
+
FileUtils.rm_rf "#{current_dir}/rubocop" if Dir.exist? "#{current_dir}/rubocop"
|
89
|
+
|
90
|
+
# Create the test_results directory to store all the results
|
91
|
+
FileUtils.mkdir_p "#{base_dir}/test_results"
|
92
|
+
end
|
93
|
+
|
94
|
+
# OpenStudio style check preparation
|
95
|
+
def pre_process_style(base_dir)
|
96
|
+
current_dir = Dir.pwd
|
97
|
+
test_results_dir = "#{base_dir}/test_results"
|
98
|
+
|
99
|
+
puts "Current directory is #{current_dir}"
|
100
|
+
puts "Pre-processing tests run in #{base_dir}"
|
101
|
+
puts "Test results will be stored in: #{test_results_dir}"
|
102
|
+
|
103
|
+
FileUtils.rm_rf "#{test_results_dir}/openstudio_style" if Dir.exist? "#{test_results_dir}/openstudio_style"
|
104
|
+
FileUtils.rm_rf "#{base_dir}/openstudio_style" if Dir.exist? "#{base_dir}/openstudio_style"
|
105
|
+
FileUtils.rm_rf "#{current_dir}/openstudio_style" if Dir.exist? "#{current_dir}/openstudio_style"
|
106
|
+
|
107
|
+
# Create the test_results directory to store all the results
|
108
|
+
FileUtils.mkdir_p "#{base_dir}/test_results"
|
109
|
+
end
|
110
|
+
|
111
|
+
def run_style(base_dir)
|
112
|
+
style = OpenStudioMeasureTester::OpenStudioStyle.new("#{base_dir}/**/measure.rb")
|
113
|
+
style.save_results
|
114
|
+
end
|
115
|
+
|
116
|
+
# Post process the various results and save them into the base_dir
|
117
|
+
def post_process_results(base_dir)
|
118
|
+
current_dir = Dir.pwd
|
119
|
+
test_results_dir = "#{base_dir}/test_results"
|
120
|
+
|
121
|
+
puts "Current directory: #{current_dir}"
|
122
|
+
puts "Post-processing tests run in: #{base_dir}"
|
123
|
+
puts "Test results will be stored in: #{test_results_dir}"
|
124
|
+
|
125
|
+
FileUtils.mkdir_p test_results_dir
|
126
|
+
|
127
|
+
results = OpenStudioMeasureTester::OpenStudioTestingResult.new(current_dir, test_results_dir)
|
128
|
+
results.save_results # one single file for dashboard
|
129
|
+
|
130
|
+
# call the create dashboard command now that we have results
|
131
|
+
dashboard(base_dir)
|
132
|
+
|
133
|
+
# return the results exit code
|
134
|
+
return results.exit_code
|
135
|
+
end
|
136
|
+
|
137
|
+
# Run ERB to create the dashboard
|
138
|
+
def dashboard(base_dir)
|
139
|
+
template = OpenStudioMeasureTester::Dashboard.new(base_dir)
|
140
|
+
template.render
|
141
|
+
end
|
142
|
+
|
143
|
+
def setup_subtasks(name)
|
144
|
+
namespace name do
|
145
|
+
task :prepare_minitest do
|
146
|
+
pre_process_minitest(Rake.application.original_dir)
|
147
|
+
end
|
148
|
+
|
149
|
+
task :prepare_rubocop do
|
150
|
+
# copy over the .rubocop.yml file
|
151
|
+
shared_rubocop_file = File.expand_path('../../.rubocop.yml', File.dirname(__FILE__))
|
152
|
+
dest_file = "#{Dir.pwd}/.rubocop.yml"
|
153
|
+
if shared_rubocop_file != dest_file
|
154
|
+
FileUtils.copy(shared_rubocop_file, dest_file)
|
155
|
+
end
|
156
|
+
pre_process_rubocop(Rake.application.original_dir)
|
157
|
+
end
|
158
|
+
|
159
|
+
task :prepare_style do
|
160
|
+
pre_process_style(Rake.application.original_dir)
|
161
|
+
end
|
162
|
+
|
163
|
+
task style_core: [] do
|
164
|
+
run_style(Rake.application.original_dir)
|
165
|
+
end
|
166
|
+
|
167
|
+
task :post_process_core do
|
168
|
+
post_process_results(Rake.application.original_dir)
|
169
|
+
end
|
170
|
+
|
171
|
+
Rake::TestTask.new(:test_core_command) do |task|
|
172
|
+
task.options = '--ci-reporter'
|
173
|
+
task.description = 'Run measures tests recursively from current directory'
|
174
|
+
task.pattern = [
|
175
|
+
"#{Rake.application.original_dir}/**/*_test.rb",
|
176
|
+
"#{Rake.application.original_dir}/**/*_Test.rb"
|
177
|
+
]
|
178
|
+
task.verbose = true
|
179
|
+
end
|
180
|
+
|
181
|
+
task :test_core do
|
182
|
+
begin
|
183
|
+
Rake.application['openstudio:test_core_command'].invoke
|
184
|
+
rescue StandardError
|
185
|
+
puts 'Test failures in openstudio:test. Will continue to post-processing.'
|
186
|
+
ensure
|
187
|
+
Rake.application['openstudio:test_core_command'].reenable
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# The .rubocop.yml file downloads the RuboCop rules from the OpenStudio-resources repo.
|
192
|
+
# This may cause an issue if the Gem directory does not have write access.
|
193
|
+
RuboCop::RakeTask.new(:rubocop_core) do |task|
|
194
|
+
task.options = ['--no-color', '--out=rubocop/rubocop-results.xml', '--format=simple']
|
195
|
+
task.formatters = ['RuboCop::Formatter::CheckstyleFormatter']
|
196
|
+
task.requires = ['rubocop/formatter/checkstyle_formatter']
|
197
|
+
# Run the rake at the original root directory
|
198
|
+
task.patterns = ["#{Rake.application.original_dir}/**/*.rb"]
|
199
|
+
# don't abort rake on failure
|
200
|
+
task.fail_on_error = false
|
201
|
+
end
|
202
|
+
|
203
|
+
desc 'Run OpenStudio Measure Unit Tests'
|
204
|
+
task test: ['openstudio:prepare_minitest', 'openstudio:test_core'] do
|
205
|
+
exit_status = post_process_results(Rake.application.original_dir)
|
206
|
+
exit exit_status
|
207
|
+
end
|
208
|
+
|
209
|
+
# Need to create a namespace so that we can have openstudio:rubocop and openstudio:rubocop:auto_correct.
|
210
|
+
namespace :rubocop do
|
211
|
+
task check: ['openstudio:prepare_rubocop', 'openstudio:rubocop_core'] do
|
212
|
+
exit_status = post_process_results(Rake.application.original_dir)
|
213
|
+
exit exit_status
|
214
|
+
end
|
215
|
+
|
216
|
+
desc 'Run RuboCop Auto Correct on Measures'
|
217
|
+
task auto_correct: 'openstudio:rubocop_core:auto_correct'
|
218
|
+
end
|
219
|
+
|
220
|
+
desc 'Run RuboCop on Measures'
|
221
|
+
task rubocop: 'openstudio:rubocop:check'
|
222
|
+
|
223
|
+
desc 'Run OpenStudio Style Checks'
|
224
|
+
task style: ['openstudio:prepare_style', 'openstudio:style_core'] do
|
225
|
+
exit_status = post_process_results(Rake.application.original_dir)
|
226
|
+
exit exit_status
|
227
|
+
end
|
228
|
+
|
229
|
+
desc 'Post process results into one directory'
|
230
|
+
task :post_process do
|
231
|
+
exit_status = post_process_results(Rake.application.original_dir)
|
232
|
+
exit exit_status
|
233
|
+
end
|
234
|
+
|
235
|
+
desc 'Generate dashboard'
|
236
|
+
task :dashboard do
|
237
|
+
dashboard(Rake.application.original_dir)
|
238
|
+
end
|
239
|
+
|
240
|
+
desc 'Run MiniTest, Coverage, RuboCop, and Style on measures, then dashboard results'
|
241
|
+
task all: ['openstudio:prepare_minitest',
|
242
|
+
'openstudio:test_core',
|
243
|
+
'openstudio:prepare_rubocop',
|
244
|
+
'openstudio:rubocop_core',
|
245
|
+
'openstudio:prepare_style',
|
246
|
+
'openstudio:style_core'] do
|
247
|
+
exit_status = post_process_results(Rake.application.original_dir)
|
248
|
+
exit exit_status
|
249
|
+
end
|
250
|
+
|
251
|
+
# Hide the core tasks from being displayed when calling rake -T
|
252
|
+
Rake::Task['openstudio:rubocop_core'].clear_comments
|
253
|
+
Rake::Task['openstudio:test_core_command'].clear_comments
|
254
|
+
Rake::Task['openstudio:rubocop_core:auto_correct'].clear_comments
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
5
|
+
# following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
8
|
+
# disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
11
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
12
|
+
#
|
13
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior written permission from the respective party.
|
15
|
+
#
|
16
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
|
17
|
+
# works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
|
18
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
21
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
|
23
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25
|
+
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
########################################################################################################################
|
28
|
+
|
29
|
+
module OpenStudioMeasureTester
|
30
|
+
class RubocopResult
|
31
|
+
attr_reader :error_status
|
32
|
+
|
33
|
+
attr_reader :file_issues
|
34
|
+
attr_reader :file_info
|
35
|
+
attr_reader :file_warnings
|
36
|
+
attr_reader :file_errors
|
37
|
+
|
38
|
+
attr_reader :total_measures
|
39
|
+
attr_reader :total_files
|
40
|
+
|
41
|
+
attr_reader :total_issues
|
42
|
+
attr_reader :total_info
|
43
|
+
attr_reader :total_warnings
|
44
|
+
attr_reader :total_errors
|
45
|
+
|
46
|
+
attr_reader :summary
|
47
|
+
attr_reader :by_measure
|
48
|
+
|
49
|
+
def initialize(path_to_results)
|
50
|
+
|
51
|
+
@path_to_results = path_to_results
|
52
|
+
@error_status = false
|
53
|
+
@total_files = 0
|
54
|
+
@total_issues = 0
|
55
|
+
@total_errors = 0
|
56
|
+
@total_warnings = 0
|
57
|
+
@total_info = 0
|
58
|
+
@total_measures = 0
|
59
|
+
|
60
|
+
@summary = {}
|
61
|
+
|
62
|
+
@by_measure = {}
|
63
|
+
|
64
|
+
parse_results
|
65
|
+
to_file
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_results
|
70
|
+
# needs rescue
|
71
|
+
Dir["#{@path_to_results}/rubocop-results.xml"].each do |file|
|
72
|
+
puts "Parsing Rubocop report #{file}"
|
73
|
+
hash = Hash.from_xml(File.read(file))
|
74
|
+
|
75
|
+
# get measure names
|
76
|
+
measure_names = []
|
77
|
+
#cn= ''
|
78
|
+
hash['checkstyle']['file'].each do |key, data|
|
79
|
+
parts = key['name'].split('/')
|
80
|
+
if parts.last == 'measure.rb'
|
81
|
+
name = parts[-2]
|
82
|
+
measure_names << name
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
@total_measures = measure_names.length
|
87
|
+
@total_files = hash['checkstyle']['file'].length
|
88
|
+
|
89
|
+
measure_names.each do |measure_name|
|
90
|
+
|
91
|
+
#cn= ''
|
92
|
+
results = hash['checkstyle']['file'].select {|data| data['name'].include? measure_name }
|
93
|
+
|
94
|
+
mhash = {}
|
95
|
+
mhash['measure_issues'] = 0
|
96
|
+
mhash['measure_info'] = 0
|
97
|
+
mhash['measure_warnings'] = 0
|
98
|
+
mhash['measure_errors'] = 0
|
99
|
+
mhash['files'] = []
|
100
|
+
|
101
|
+
results.each do |key, data|
|
102
|
+
fhash = {}
|
103
|
+
fhash['file_name'] = key['name'].split('/')[-1]
|
104
|
+
fhash['violations'] = []
|
105
|
+
|
106
|
+
# get the class name
|
107
|
+
# if fhash['file_name'] == 'measure.rb'
|
108
|
+
# File.readlines(key['name']).each do |line|
|
109
|
+
# if (line.include? 'class') && line.split(' ')[0] == 'class'
|
110
|
+
# cn = line.split(' ')[1]
|
111
|
+
# break
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
|
116
|
+
if key['error']
|
117
|
+
@file_issues = 0
|
118
|
+
@file_info = 0
|
119
|
+
@file_warnings = 0
|
120
|
+
@file_errors = 0
|
121
|
+
|
122
|
+
violations = []
|
123
|
+
|
124
|
+
if key['error'].class == Array
|
125
|
+
@file_issues = key['error'].length
|
126
|
+
key['error'].each do |s|
|
127
|
+
|
128
|
+
if s['severity'] === "info"
|
129
|
+
@file_info += 1
|
130
|
+
elsif s['severity'] === "warning"
|
131
|
+
@file_warnings += 1
|
132
|
+
elsif s['severity'] === "error" #TODO: look up complete list of codes
|
133
|
+
@file_errors += 1
|
134
|
+
end
|
135
|
+
violations << {line: s['line'], column: s['column'], severity: s['severity'], message: s['message']}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
if key['error'].class == Hash
|
140
|
+
@file_issues = 1
|
141
|
+
if key['error']['severity'] === "info"
|
142
|
+
@file_info += 1
|
143
|
+
elsif key['error']['severity'] === "warning"
|
144
|
+
@file_warnings += 1
|
145
|
+
elsif key['error']['severity'] === "error"
|
146
|
+
@file_errors += 1
|
147
|
+
end
|
148
|
+
violations << {line: key['error']['line'], column: key['error']['column'], severity: key['error']['severity'], message: key['error']['message']}
|
149
|
+
end
|
150
|
+
|
151
|
+
fhash['issues'] = @file_issues
|
152
|
+
fhash['info'] = @file_info
|
153
|
+
fhash['warning'] = @file_warnings
|
154
|
+
fhash['error'] = @file_errors
|
155
|
+
fhash['violations'] = violations
|
156
|
+
|
157
|
+
mhash['measure_issues'] += @file_issues
|
158
|
+
mhash['measure_info'] += @file_info
|
159
|
+
mhash['measure_warnings'] += @file_warnings
|
160
|
+
mhash['measure_errors'] += @file_errors
|
161
|
+
|
162
|
+
@total_issues += @file_issues
|
163
|
+
@total_info += @file_info
|
164
|
+
@total_warnings += @file_warnings
|
165
|
+
@total_errors += @file_errors
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
mhash['files'] << fhash
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
#@summary << mhash
|
174
|
+
#@by_measure[cn] = mhash
|
175
|
+
@by_measure[measure_name] = mhash
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
puts "total files: #{total_files}"
|
182
|
+
puts "total issues: #{@total_issues} (#{@total_info} info, #{@total_warnings} warnings, #{@total_errors} errors)"
|
183
|
+
|
184
|
+
# TODO: still need to get errors ID'd
|
185
|
+
@error_status = true if @total_errors > 0
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_hash
|
190
|
+
results = {};
|
191
|
+
results['total_measures'] = @total_measures
|
192
|
+
results['total_files'] = @total_files
|
193
|
+
results['total_issues'] = @total_issues
|
194
|
+
results['total_info'] = @total_info
|
195
|
+
results['total_warnings'] = @total_warnings
|
196
|
+
results['total_errors'] = @total_errors
|
197
|
+
results['by_measure'] = @by_measure
|
198
|
+
|
199
|
+
results
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_file
|
203
|
+
# save as a json and have something else parse it/plot it.
|
204
|
+
res_hash = to_hash
|
205
|
+
@summary = res_hash
|
206
|
+
FileUtils.mkdir_p "#{@path_to_results}/" unless Dir.exist? "#{@path_to_results}/"
|
207
|
+
File.open("#{@path_to_results}/rubocop.json", 'w') do |file|
|
208
|
+
file << JSON.pretty_generate(res_hash)
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|