pmdtester 1.0.0.pre.beta3 → 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 +4 -4
- data/.hoerc +1 -1
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +7 -8
- data/.travis.yml +20 -2
- data/Gemfile +1 -12
- data/History.md +37 -0
- data/Manifest.txt +6 -0
- data/README.rdoc +72 -46
- data/Rakefile +23 -13
- data/lib/pmdtester.rb +8 -1
- data/lib/pmdtester/builders/diff_builder.rb +8 -7
- data/lib/pmdtester/builders/diff_report/configerrors.rb +50 -0
- data/lib/pmdtester/builders/diff_report/errors.rb +71 -0
- data/lib/pmdtester/builders/diff_report/violations.rb +77 -0
- data/lib/pmdtester/builders/diff_report_builder.rb +23 -149
- data/lib/pmdtester/builders/html_report_builder.rb +23 -0
- data/lib/pmdtester/builders/pmd_report_builder.rb +69 -23
- data/lib/pmdtester/builders/rule_set_builder.rb +3 -2
- data/lib/pmdtester/builders/simple_progress_logger.rb +27 -0
- data/lib/pmdtester/builders/summary_report_builder.rb +19 -5
- data/lib/pmdtester/cmd.rb +15 -1
- data/lib/pmdtester/parsers/options.rb +6 -2
- data/lib/pmdtester/parsers/pmd_report_document.rb +11 -5
- data/lib/pmdtester/pmd_branch_detail.rb +17 -3
- data/lib/pmdtester/pmd_configerror.rb +63 -0
- data/lib/pmdtester/pmd_violation.rb +2 -0
- data/lib/pmdtester/project.rb +35 -3
- data/lib/pmdtester/report_diff.rb +67 -21
- data/lib/pmdtester/runner.rb +40 -15
- data/pmdtester.gemspec +73 -0
- metadata +62 -25
@@ -4,6 +4,7 @@ module PmdTester
|
|
4
4
|
# This class is the parent of all classes which is used to build html report
|
5
5
|
class HtmlReportBuilder
|
6
6
|
CSS_SRC_DIR = ResourceLocator.locate('resources/css')
|
7
|
+
NO_DIFFERENCES_MESSAGE = 'No differences found!'
|
7
8
|
|
8
9
|
def build_html_report(title_name)
|
9
10
|
html_builder = Nokogiri::HTML::Builder.new do |doc|
|
@@ -25,9 +26,31 @@ module PmdTester
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
def build_table_head(doc, *columns)
|
30
|
+
doc.thead do
|
31
|
+
doc.tr do
|
32
|
+
columns.each do |column|
|
33
|
+
doc.th column
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_table_anchor_column(doc, prefix, index)
|
40
|
+
doc.td do
|
41
|
+
doc.a(id: "#{prefix}#{index}", href: "##{prefix}#{index}") { doc.text '#' }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
28
45
|
def copy_css(report_dir)
|
29
46
|
css_dest_dir = "#{report_dir}/css"
|
30
47
|
FileUtils.copy_entry(CSS_SRC_DIR, css_dest_dir)
|
31
48
|
end
|
49
|
+
|
50
|
+
def build_table_content_for(doc, removed_size, new_size)
|
51
|
+
doc.font(color: 'red') { doc.text "-#{removed_size}" }
|
52
|
+
doc.text ' | '
|
53
|
+
doc.font(color: 'green') { doc.text "+#{new_size}" }
|
54
|
+
end
|
32
55
|
end
|
33
56
|
end
|
@@ -1,17 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
+
require 'rufus-scheduler'
|
4
5
|
|
5
6
|
module PmdTester
|
6
7
|
# Building pmd xml reports according to a list of standard
|
7
8
|
# projects and branch of pmd source code
|
8
9
|
class PmdReportBuilder
|
9
10
|
include PmdTester
|
10
|
-
def initialize(branch_config, projects, local_git_repo, pmd_branch_name)
|
11
|
+
def initialize(branch_config, projects, local_git_repo, pmd_branch_name, threads = 1)
|
11
12
|
@branch_config = branch_config
|
12
13
|
@projects = projects
|
13
14
|
@local_git_repo = local_git_repo
|
14
15
|
@pmd_branch_name = pmd_branch_name
|
16
|
+
@threads = threads
|
15
17
|
@pwd = Dir.getwd
|
16
18
|
|
17
19
|
@pmd_branch_details = PmdBranchDetail.new(pmd_branch_name)
|
@@ -28,7 +30,7 @@ module PmdTester
|
|
28
30
|
Cmd.execute(reset_cmd)
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
33
|
+
def clone_projects
|
32
34
|
logger.info 'Cloning projects started'
|
33
35
|
|
34
36
|
@projects.each do |project|
|
@@ -46,29 +48,58 @@ module PmdTester
|
|
46
48
|
end
|
47
49
|
logger.info "Cloning #{project.name} completed"
|
48
50
|
end
|
51
|
+
|
52
|
+
logger.info 'Cloning projects completed'
|
49
53
|
end
|
50
54
|
|
51
55
|
def get_pmd_binary_file
|
52
|
-
logger.info
|
56
|
+
logger.info "#{@pmd_branch_name}: Start packaging PMD"
|
53
57
|
Dir.chdir(@local_git_repo) do
|
54
|
-
|
55
|
-
Cmd.execute(
|
58
|
+
current_head_sha = Cmd.execute('git rev-parse HEAD')
|
59
|
+
current_branch_sha = Cmd.execute("git rev-parse #{@pmd_branch_name}")
|
56
60
|
|
57
|
-
@
|
58
|
-
@pmd_branch_details.branch_last_message = get_last_commit_message
|
61
|
+
@pmd_version = determine_pmd_version
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
# in case we are already on the correct branch
|
64
|
+
# and a binary zip already exists...
|
65
|
+
if current_head_sha == current_branch_sha &&
|
66
|
+
File.exist?("pmd-dist/target/pmd-bin-#{@pmd_version}.zip")
|
67
|
+
logger.warn "#{@pmd_branch_name}: Skipping packaging - zip for " \
|
68
|
+
"#{@pmd_version} already exists"
|
69
|
+
else
|
70
|
+
build_pmd
|
71
|
+
end
|
63
72
|
|
64
|
-
|
65
|
-
|
66
|
-
@pmd_version = Cmd.execute(version_cmd)
|
73
|
+
@pmd_branch_details.branch_last_sha = get_last_commit_sha
|
74
|
+
@pmd_branch_details.branch_last_message = get_last_commit_message
|
67
75
|
|
76
|
+
logger.info "#{@pmd_branch_name}: Extracting the zip"
|
68
77
|
unzip_cmd = "unzip -qo pmd-dist/target/pmd-bin-#{@pmd_version}.zip -d #{@pwd}/target"
|
69
78
|
Cmd.execute(unzip_cmd)
|
70
79
|
end
|
71
|
-
logger.info
|
80
|
+
logger.info "#{@pmd_branch_name}: Packaging PMD completed"
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_pmd
|
84
|
+
logger.info "#{@pmd_branch_name}: Checking out the branch"
|
85
|
+
checkout_cmd = "git checkout #{@pmd_branch_name}"
|
86
|
+
Cmd.execute(checkout_cmd)
|
87
|
+
|
88
|
+
# determine the version again - it might be different in the other branch
|
89
|
+
@pmd_version = determine_pmd_version
|
90
|
+
|
91
|
+
logger.info "#{@pmd_branch_name}: Building PMD #{@pmd_version}..."
|
92
|
+
package_cmd = './mvnw clean package' \
|
93
|
+
' -Dmaven.test.skip=true' \
|
94
|
+
' -Dmaven.javadoc.skip=true' \
|
95
|
+
' -Dmaven.source.skip=true'
|
96
|
+
Cmd.execute(package_cmd)
|
97
|
+
end
|
98
|
+
|
99
|
+
def determine_pmd_version
|
100
|
+
version_cmd = "./mvnw -q -Dexec.executable=\"echo\" -Dexec.args='${project.version}' " \
|
101
|
+
'--non-recursive org.codehaus.mojo:exec-maven-plugin:1.5.0:exec'
|
102
|
+
Cmd.execute(version_cmd)
|
72
103
|
end
|
73
104
|
|
74
105
|
def get_last_commit_sha
|
@@ -81,26 +112,40 @@ module PmdTester
|
|
81
112
|
Cmd.execute(get_last_commit_message_cmd)
|
82
113
|
end
|
83
114
|
|
84
|
-
def generate_pmd_report(
|
115
|
+
def generate_pmd_report(project)
|
85
116
|
run_path = "target/pmd-bin-#{@pmd_version}/bin/run.sh"
|
86
|
-
pmd_cmd = "#{run_path} pmd -d #{
|
87
|
-
"-
|
117
|
+
pmd_cmd = "#{run_path} pmd -d #{project.local_source_path} -f xml " \
|
118
|
+
"-R #{project.get_config_path(@pmd_branch_name)} " \
|
119
|
+
"-r #{project.get_pmd_report_path(@pmd_branch_name)} " \
|
120
|
+
"-failOnViolation false -t #{@threads}"
|
88
121
|
start_time = Time.now
|
89
122
|
Cmd.execute(pmd_cmd)
|
90
123
|
end_time = Time.now
|
91
124
|
[end_time - start_time, end_time]
|
92
125
|
end
|
93
126
|
|
127
|
+
def generate_config_for(project)
|
128
|
+
doc = Nokogiri::XML(File.read(@branch_config))
|
129
|
+
ruleset = doc.at_css('ruleset')
|
130
|
+
project.exclude_pattern.each do |exclude_pattern|
|
131
|
+
ruleset.add_child("<exclude-pattern>#{exclude_pattern}</exclude-pattern>")
|
132
|
+
end
|
133
|
+
|
134
|
+
File.open(project.get_config_path(@pmd_branch_name), 'w') do |x|
|
135
|
+
x << doc.to_s
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
94
139
|
def generate_pmd_reports
|
95
140
|
logger.info "Generating PMD report started -- branch #{@pmd_branch_name}"
|
96
|
-
get_pmd_binary_file
|
97
141
|
|
98
142
|
sum_time = 0
|
99
143
|
@projects.each do |project|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
144
|
+
progress_logger = SimpleProgressLogger.new(project.name)
|
145
|
+
progress_logger.start
|
146
|
+
generate_config_for(project)
|
147
|
+
execution_time, end_time = generate_pmd_report(project)
|
148
|
+
progress_logger.stop
|
104
149
|
sum_time += execution_time
|
105
150
|
|
106
151
|
report_details = PmdReportDetail.new
|
@@ -117,7 +162,8 @@ module PmdTester
|
|
117
162
|
end
|
118
163
|
|
119
164
|
def build
|
120
|
-
|
165
|
+
clone_projects
|
166
|
+
get_pmd_binary_file
|
121
167
|
generate_pmd_reports
|
122
168
|
end
|
123
169
|
end
|
@@ -29,6 +29,7 @@ module PmdTester
|
|
29
29
|
output_filter_set(rule_sets)
|
30
30
|
build_config_file(rule_sets)
|
31
31
|
logger.debug "Dynamic configuration: #{[rule_sets]}"
|
32
|
+
rule_sets
|
32
33
|
end
|
33
34
|
|
34
35
|
def output_filter_set(rule_sets)
|
@@ -46,7 +47,7 @@ module PmdTester
|
|
46
47
|
base = @options.base_branch
|
47
48
|
patch = @options.patch_branch
|
48
49
|
# We only need to support git here, since PMD's repo is using git.
|
49
|
-
diff_cmd = "git diff --name-only #{base}..#{patch} -- pmd-core pmd-java"
|
50
|
+
diff_cmd = "git diff --name-only #{base}..#{patch} -- pmd-core/src/main pmd-java/src/main"
|
50
51
|
filenames = Cmd.execute(diff_cmd)
|
51
52
|
end
|
52
53
|
filenames.split("\n")
|
@@ -79,7 +80,7 @@ module PmdTester
|
|
79
80
|
def build_config_file(rule_sets)
|
80
81
|
if rule_sets.empty?
|
81
82
|
logger.info NO_JAVA_RULES_CHANGED_MESSAGE
|
82
|
-
|
83
|
+
return
|
83
84
|
end
|
84
85
|
|
85
86
|
doc = Nokogiri::XML(File.read(PATH_TO_ALL_JAVA_RULES))
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rufus-scheduler'
|
4
|
+
|
5
|
+
module PmdTester
|
6
|
+
# Helper class that provides a simple progress logging
|
7
|
+
class SimpleProgressLogger
|
8
|
+
include PmdTester
|
9
|
+
def initialize(project_name)
|
10
|
+
@project_name = project_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
logger.info "Starting to generate #{@project_name}'s PMD report"
|
15
|
+
message_counter = 1
|
16
|
+
@scheduler = Rufus::Scheduler.new
|
17
|
+
@scheduler.every '2m' do
|
18
|
+
logger.info "Still generating #{@project_name}'s PMD report (#{message_counter})..."
|
19
|
+
message_counter += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop
|
24
|
+
@scheduler.shutdown
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -29,7 +29,6 @@ module PmdTester
|
|
29
29
|
def get_branch_details(branch_name)
|
30
30
|
details = PmdBranchDetail.new(branch_name)
|
31
31
|
details.load
|
32
|
-
details
|
33
32
|
end
|
34
33
|
|
35
34
|
def build_body(doc)
|
@@ -71,6 +70,10 @@ module PmdTester
|
|
71
70
|
@patch_details.branch_last_message)
|
72
71
|
build_branch_table_row(doc, 'total execution time', @base_details.format_execution_time,
|
73
72
|
@patch_details.format_execution_time)
|
73
|
+
build_branch_table_row(doc, 'jdk version', @base_details.jdk_version,
|
74
|
+
@patch_details.jdk_version)
|
75
|
+
build_branch_table_row(doc, 'language', @base_details.language,
|
76
|
+
@patch_details.language)
|
74
77
|
build_branch_config_table_row(doc)
|
75
78
|
end
|
76
79
|
end
|
@@ -122,8 +125,9 @@ module PmdTester
|
|
122
125
|
doc.tr do
|
123
126
|
doc.th 'project name'
|
124
127
|
doc.th 'project branch/tag'
|
125
|
-
doc.th '
|
126
|
-
doc.th '
|
128
|
+
doc.th 'removed|new errors size'
|
129
|
+
doc.th 'removed|new violations size'
|
130
|
+
doc.th 'removed|new configerrors size'
|
127
131
|
end
|
128
132
|
end
|
129
133
|
end
|
@@ -136,8 +140,18 @@ module PmdTester
|
|
136
140
|
doc.a(href: project.diff_report_index_ref_path) { doc.text project.name }
|
137
141
|
end
|
138
142
|
doc.td project.tag
|
139
|
-
doc.td
|
140
|
-
|
143
|
+
doc.td do
|
144
|
+
build_table_content_for(doc, project.removed_errors_size,
|
145
|
+
project.new_errors_size)
|
146
|
+
end
|
147
|
+
doc.td do
|
148
|
+
build_table_content_for(doc, project.removed_violations_size,
|
149
|
+
project.new_violations_size)
|
150
|
+
end
|
151
|
+
doc.td do
|
152
|
+
build_table_content_for(doc, project.removed_configerrors_size,
|
153
|
+
project.new_configerrors_size)
|
154
|
+
end
|
141
155
|
end
|
142
156
|
end
|
143
157
|
end
|
data/lib/pmdtester/cmd.rb
CHANGED
@@ -7,20 +7,34 @@ module PmdTester
|
|
7
7
|
class Cmd
|
8
8
|
extend PmdTester
|
9
9
|
def self.execute(cmd)
|
10
|
+
stdout, _stderr, _status = internal_execute(cmd)
|
11
|
+
stdout&.chomp!
|
12
|
+
stdout
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.stderr_of(cmd)
|
16
|
+
_stdout, stderr, _status = internal_execute(cmd)
|
17
|
+
stderr
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.internal_execute(cmd)
|
10
21
|
logger.debug "execute command '#{cmd}'"
|
11
22
|
|
12
23
|
stdout, stderr, status = Open3.capture3("#{cmd};")
|
13
24
|
|
14
25
|
logger.debug stdout
|
15
26
|
unless status.success?
|
27
|
+
logger.error stdout
|
16
28
|
logger.error stderr
|
17
29
|
raise CmdException.new(cmd, stderr)
|
18
30
|
end
|
19
31
|
|
20
32
|
stdout&.chomp!
|
21
33
|
|
22
|
-
stdout
|
34
|
+
[stdout, stderr, status]
|
23
35
|
end
|
36
|
+
|
37
|
+
private_class_method :internal_execute
|
24
38
|
end
|
25
39
|
|
26
40
|
# The exception should be raised when the shell command failed.
|
@@ -25,6 +25,7 @@ module PmdTester
|
|
25
25
|
attr_reader :config
|
26
26
|
attr_reader :project_list
|
27
27
|
attr_reader :mode
|
28
|
+
attr_reader :threads
|
28
29
|
attr_reader :html_flag
|
29
30
|
attr_reader :auto_config_flag
|
30
31
|
attr_reader :debug_flag
|
@@ -40,6 +41,7 @@ module PmdTester
|
|
40
41
|
@config = options[:c]
|
41
42
|
@project_list = options[:l]
|
42
43
|
@mode = options[:m]
|
44
|
+
@threads = options[:t]
|
43
45
|
@html_flag = options[:f]
|
44
46
|
@auto_config_flag = options[:a]
|
45
47
|
@debug_flag = options[:d]
|
@@ -61,8 +63,8 @@ module PmdTester
|
|
61
63
|
single: Set this option to 'single' if your patch branch contains changes
|
62
64
|
for any option that can't work on master/base branch
|
63
65
|
online: Set this option to 'online' if you want to download
|
64
|
-
|
65
|
-
local: Default option is 'local'
|
66
|
+
the PMD report of master/base branch rather than generating it locally
|
67
|
+
local: Default option is 'local', PMD reports for the base and patch branches are generated locally.
|
66
68
|
DOC
|
67
69
|
|
68
70
|
Slop.parse argv do |o|
|
@@ -79,6 +81,8 @@ module PmdTester
|
|
79
81
|
'path to the file which contains the list of standard projects',
|
80
82
|
default: DEFAULT_LIST_PATH
|
81
83
|
o.string '-m', '--mode', mode_message, default: 'local'
|
84
|
+
o.integer '-t', '--threads', 'Sets the number of threads used by PMD.' \
|
85
|
+
' Set threads to 0 to disable multi-threading processing.', default: 1
|
82
86
|
o.bool '-f', '--html-flag',
|
83
87
|
'whether to not generate the html diff report in single mode'
|
84
88
|
o.bool '-a', '--auto-gen-config',
|
@@ -7,12 +7,15 @@ module PmdTester
|
|
7
7
|
class PmdReportDocument < Nokogiri::XML::SAX::Document
|
8
8
|
attr_reader :violations
|
9
9
|
attr_reader :errors
|
10
|
+
attr_reader :configerrors
|
10
11
|
def initialize(branch_name, working_dir, filter_set = nil)
|
11
12
|
@violations = PmdViolations.new
|
12
13
|
@errors = PmdErrors.new
|
14
|
+
@configerrors = PmdConfigErrors.new
|
13
15
|
@current_violations = []
|
14
16
|
@current_violation = nil
|
15
17
|
@current_error = nil
|
18
|
+
@current_configerror = nil
|
16
19
|
@current_element = ''
|
17
20
|
@filename = ''
|
18
21
|
@filter_set = filter_set
|
@@ -34,6 +37,8 @@ module PmdTester
|
|
34
37
|
@current_filename = remove_work_dir!(attrs['filename'])
|
35
38
|
remove_work_dir!(attrs['msg'])
|
36
39
|
@current_error = PmdError.new(attrs, @branch_name)
|
40
|
+
when 'configerror'
|
41
|
+
@current_configerror = PmdConfigError.new(attrs, @branch_name)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
@@ -42,15 +47,13 @@ module PmdTester
|
|
42
47
|
end
|
43
48
|
|
44
49
|
def characters(string)
|
45
|
-
@current_violation
|
50
|
+
@current_violation&.text = string
|
46
51
|
end
|
47
52
|
|
48
53
|
def end_element(name)
|
49
54
|
case name
|
50
55
|
when 'file'
|
51
|
-
|
52
|
-
@violations.add_violations_by_filename(@current_filename, @current_violations)
|
53
|
-
end
|
56
|
+
@violations.add_violations_by_filename(@current_filename, @current_violations)
|
54
57
|
@current_filename = nil
|
55
58
|
when 'violation'
|
56
59
|
@current_violations.push(@current_violation) if match_filter_set?(@current_violation)
|
@@ -59,12 +62,15 @@ module PmdTester
|
|
59
62
|
@errors.add_error_by_filename(@current_filename, @current_error)
|
60
63
|
@current_filename = nil
|
61
64
|
@current_error = nil
|
65
|
+
when 'configerror'
|
66
|
+
@configerrors.add_error(@current_configerror)
|
67
|
+
@current_configerror = nil
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
65
71
|
def cdata_block(string)
|
66
72
|
remove_work_dir!(string)
|
67
|
-
@current_error
|
73
|
+
@current_error&.text = string
|
68
74
|
end
|
69
75
|
|
70
76
|
def match_filter_set?(violation)
|
@@ -5,11 +5,15 @@ require 'json'
|
|
5
5
|
module PmdTester
|
6
6
|
# This class represents all details about branch of pmd
|
7
7
|
class PmdBranchDetail
|
8
|
+
include PmdTester
|
9
|
+
|
8
10
|
attr_accessor :branch_last_sha
|
9
11
|
attr_accessor :branch_last_message
|
10
12
|
attr_accessor :branch_name
|
11
13
|
# The branch's execution time on all standard projects
|
12
14
|
attr_accessor :execution_time
|
15
|
+
attr_reader :jdk_version
|
16
|
+
attr_reader :language
|
13
17
|
|
14
18
|
def self.branch_filename(branch_name)
|
15
19
|
branch_name&.tr('/', '_')
|
@@ -22,6 +26,9 @@ module PmdTester
|
|
22
26
|
branch_filename = PmdBranchDetail.branch_filename(branch_name)
|
23
27
|
@base_branch_dir = "target/reports/#{branch_filename}" unless @branch_name.nil?
|
24
28
|
@execution_time = 0
|
29
|
+
# the result of command 'java -version' is going to stderr
|
30
|
+
@jdk_version = Cmd.stderr_of('java -version')
|
31
|
+
@language = ENV['LANG']
|
25
32
|
end
|
26
33
|
|
27
34
|
def load
|
@@ -31,20 +38,27 @@ module PmdTester
|
|
31
38
|
@branch_last_message = hash['branch_last_message']
|
32
39
|
@branch_name = hash['branch_name']
|
33
40
|
@execution_time = hash['execution_time']
|
34
|
-
hash
|
41
|
+
@jdk_version = hash['jdk_version']
|
42
|
+
@language = hash['language']
|
35
43
|
else
|
36
|
-
|
44
|
+
@jdk_version = ''
|
45
|
+
@language = ''
|
46
|
+
logger.warn "#{branch_details_path} doesn't exist!"
|
37
47
|
end
|
48
|
+
self
|
38
49
|
end
|
39
50
|
|
40
51
|
def save
|
41
52
|
hash = { branch_last_sha: @branch_last_sha,
|
42
53
|
branch_last_message: @branch_last_message,
|
43
54
|
branch_name: @branch_name,
|
44
|
-
execution_time: @execution_time
|
55
|
+
execution_time: @execution_time,
|
56
|
+
jdk_version: @jdk_version,
|
57
|
+
language: @language }
|
45
58
|
file = File.new(branch_details_path, 'w')
|
46
59
|
file.puts JSON.generate(hash)
|
47
60
|
file.close
|
61
|
+
self
|
48
62
|
end
|
49
63
|
|
50
64
|
def branch_details_path
|