fastlane-plugin-code_static_analyzer 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/LICENSE +21 -0
- data/README.md +143 -0
- data/lib/assets/code_analys.sh +27 -0
- data/lib/assets/formatter.rb +31 -0
- data/lib/assets/junit_parser.rb +225 -0
- data/lib/assets/run_script.sh +13 -0
- data/lib/fastlane/plugin/code_static_analyzer.rb +17 -0
- data/lib/fastlane/plugin/code_static_analyzer/actions/code_static_analyzer_action.rb +310 -0
- data/lib/fastlane/plugin/code_static_analyzer/actions/cpd_analyzer.rb +134 -0
- data/lib/fastlane/plugin/code_static_analyzer/actions/ruby_analyzer.rb +112 -0
- data/lib/fastlane/plugin/code_static_analyzer/actions/warning_analyzer.rb +156 -0
- data/lib/fastlane/plugin/code_static_analyzer/helper/code_static_analyzer_helper.rb +12 -0
- data/lib/fastlane/plugin/code_static_analyzer/version.rb +5 -0
- metadata +168 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/bin/bash -o pipefail
|
2
|
+
#!/bin/sh -e
|
3
|
+
# run_script.sh
|
4
|
+
# @desc Run shell script.
|
5
|
+
# @usage
|
6
|
+
# Parameters
|
7
|
+
# $1 - shell script you want to run
|
8
|
+
# $2 - filename with extension to store command results
|
9
|
+
|
10
|
+
{
|
11
|
+
eval $1 | tee "$2"
|
12
|
+
} &> /dev/null
|
13
|
+
exit $?
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fastlane/plugin/code_static_analyzer/version'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module CodeStaticAnalyzer
|
5
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
6
|
+
ROOT = Pathname.new(File.expand_path('../../..', __FILE__))
|
7
|
+
def self.all_classes
|
8
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# By default we want to import all available actions and helpers
|
14
|
+
# A plugin can contain any number of actions and plugins
|
15
|
+
Fastlane::CodeStaticAnalyzer.all_classes.each do |current|
|
16
|
+
require current
|
17
|
+
end
|
@@ -0,0 +1,310 @@
|
|
1
|
+
module Fastlane
|
2
|
+
require File.join CodeStaticAnalyzer::ROOT, "assets/formatter.rb"
|
3
|
+
require File.join CodeStaticAnalyzer::ROOT, "assets/junit_parser.rb"
|
4
|
+
require 'xcodeproj'
|
5
|
+
|
6
|
+
module Actions
|
7
|
+
module SharedValues
|
8
|
+
ANALYZER_STATUS = :ANALYZER_STATUS
|
9
|
+
end
|
10
|
+
|
11
|
+
class CodeStaticAnalyzerAction < Action
|
12
|
+
SUPPORTED_ANALYZER = ["xcodeWar", "rubocop", "CPD"]
|
13
|
+
RESULT_FILE = 'codeAnalysResults_analyzers.xml'
|
14
|
+
attr_accessor :checked_pmd, :checked_xcode_param, :xml_content, :run_main
|
15
|
+
|
16
|
+
def self.run(params)
|
17
|
+
@run_main = true
|
18
|
+
Actions::CodeStaticAnalyzerAction.is_pmd_installed
|
19
|
+
platform = Actions.lane_context[SharedValues::PLATFORM_NAME].to_s
|
20
|
+
@xml_content = ''
|
21
|
+
root_dir = work_dir
|
22
|
+
analyzers = params[:analyzers]
|
23
|
+
analyzers = SUPPORTED_ANALYZER if (analyzers and analyzers.empty?) or analyzers[0] == 'all'
|
24
|
+
xcode_project = params[:xcode_project_name]
|
25
|
+
xcode_workspace = params[:xcode_workspace_name]
|
26
|
+
xcode_targets = params[:xcode_targets]
|
27
|
+
# use additional checks for optional parameters, but required in specific analyzer
|
28
|
+
analyzers.each do |analyzer|
|
29
|
+
case analyzer.downcase
|
30
|
+
when 'xcodewar'
|
31
|
+
UI.user_error!("No project name for Warnings Analyzer given. Pass using `xcode_project` or configure analyzers to run using `analyzers`") if !xcode_project or (xcode_project and xcode_project.empty?) and platform != 'android'
|
32
|
+
checked_params = xcode_check_parameters(root_dir, xcode_project, xcode_workspace, xcode_targets)
|
33
|
+
xcode_project = checked_params[0]
|
34
|
+
xcode_workspace = checked_params[1]
|
35
|
+
xcode_targets = checked_params[2]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
status_rubocop = 0
|
40
|
+
status_static = 0
|
41
|
+
clear_all_files = "#{root_dir}#{params[:result_dir]}/*.*"
|
42
|
+
# clear_temp_files = "#{root_dir}#{params[:result_dir]}/*temp*.*"
|
43
|
+
sh "rm -rf #{clear_all_files}"
|
44
|
+
|
45
|
+
# Run alyzers
|
46
|
+
status_cpd = Actions::CpdAnalyzerAction.run(
|
47
|
+
result_dir: params[:result_dir],
|
48
|
+
tokens: params[:cpd_tokens],
|
49
|
+
language: params[:cpd_language],
|
50
|
+
cpd_files_to_inspect: params[:cpd_files_to_inspect],
|
51
|
+
cpd_files_to_exclude: params[:cpd_files_to_exclude]
|
52
|
+
)
|
53
|
+
analyzers.each do |analyzer|
|
54
|
+
case analyzer.downcase
|
55
|
+
when 'xcodewar'
|
56
|
+
if platform != "android"
|
57
|
+
status_static = Actions::WarningAnalyzerAction.run(
|
58
|
+
result_dir: params[:result_dir],
|
59
|
+
xcode_project_name: xcode_project,
|
60
|
+
xcode_workspace_name: xcode_workspace,
|
61
|
+
xcode_targets: xcode_targets
|
62
|
+
)
|
63
|
+
end
|
64
|
+
when 'rubocop'
|
65
|
+
status_rubocop = Actions::RubyAnalyzerAction.run(
|
66
|
+
result_dir: params[:result_dir],
|
67
|
+
ruby_files: params[:ruby_files]
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
# sh "rm -rf #{clear_temp_files}"
|
72
|
+
|
73
|
+
create_analyzers_run_result("#{root_dir}#{params[:result_dir]}/") unless @xml_content.empty?
|
74
|
+
|
75
|
+
if Actions::CodeStaticAnalyzerAction.status_to_boolean(status_cpd) &&
|
76
|
+
Actions::CodeStaticAnalyzerAction.status_to_boolean(status_static) &&
|
77
|
+
Actions::CodeStaticAnalyzerAction.status_to_boolean(status_rubocop)
|
78
|
+
Actions.lane_context[SharedValues::ANALYZER_STATUS] = true
|
79
|
+
else
|
80
|
+
Actions.lane_context[SharedValues::ANALYZER_STATUS] = false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.start_xml_content
|
85
|
+
@xml_content = ""
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.run_from_main_action
|
89
|
+
@run_main
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.analyzers_xml
|
93
|
+
@xml_content
|
94
|
+
end
|
95
|
+
|
96
|
+
class << self
|
97
|
+
attr_reader :checked_pmd
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.checked_xcode
|
101
|
+
@checked_xcode_param
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.add_xml_content(root, analyzer_name, temp_result_file, info)
|
105
|
+
UI.error "#{analyzer_name} analyzer failed to create temporary result file. More info in #{root}#{RESULT_FILE}"
|
106
|
+
new_line = JunitParser.xml_level(3)
|
107
|
+
if info.empty?
|
108
|
+
info = "Don't see #{temp_result_file} file.#{new_line}Try to run command with --verbose" \
|
109
|
+
" to see warnings made by used analyzers"
|
110
|
+
end
|
111
|
+
failures = JunitParser.add_failure('', 'unexisted result file', "#{new_line}#{info}")
|
112
|
+
@xml_content += JunitParser.add_failed_testcase("#{analyzer_name} analyzer crash", failures)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.create_analyzers_run_result(result_dir)
|
116
|
+
unless @xml_content.empty?
|
117
|
+
junit_xml = JunitParser.add_testsuite('static anlyzers', @xml_content)
|
118
|
+
JunitParser.create_junit_xml(junit_xml, "#{result_dir}/#{RESULT_FILE}")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.status_to_boolean(var)
|
123
|
+
if var == 0 or var == '0' or var == true or var == 'true'
|
124
|
+
return true
|
125
|
+
else
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.is_pmd_installed
|
131
|
+
@checked_pmd = false
|
132
|
+
begin
|
133
|
+
Actions.sh('type pmd')
|
134
|
+
rescue
|
135
|
+
UI.user_error! 'PMD not installed. Please, install PMD for using copy paste analyzer.'
|
136
|
+
end
|
137
|
+
@checked_pmd = true
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.work_dir
|
141
|
+
directory = Dir.pwd
|
142
|
+
directory + "/" unless directory.end_with? "/"
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.check_file_exist(work_dir, file, parameter_name)
|
146
|
+
if file.kind_of?(Array)
|
147
|
+
file.each do |file_path|
|
148
|
+
UI.user_error!("Unexisted path '#{work_dir}#{file_path}'. Check '#{parameter_name}' parameter. Files should be relative to work directory '#{work_dir}'") if Dir.glob("#{work_dir}#{file_path}").empty?
|
149
|
+
end
|
150
|
+
else
|
151
|
+
UI.user_error!("Unexisted path '#{work_dir}#{file}'. Check '#{parameter_name}' parameter. Files should be relative to work directory '#{work_dir}'") if Dir.glob("#{work_dir}#{file}").empty?
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.add_root_path(root, file_list, is_inspected)
|
156
|
+
file_list_str = ''
|
157
|
+
if file_list.nil? || file_list.empty?
|
158
|
+
file_list_str = "'#{root}'" if is_inspected
|
159
|
+
else
|
160
|
+
file_list.each do |file|
|
161
|
+
file_path = "#{root}#{file}"
|
162
|
+
file_path = file_path.sub("//", '/')
|
163
|
+
file_path = file_path.sub("/./", '/')
|
164
|
+
file_list_str += "'#{file_path}' "
|
165
|
+
end
|
166
|
+
end
|
167
|
+
file_list_str
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.xcode_check_parameters(root_dir, project, workspace, targets)
|
171
|
+
@checked_xcode_param = false
|
172
|
+
if Actions.lane_context[SharedValues::PLATFORM_NAME] == 'android'
|
173
|
+
UI.user_error! 'This warning_analyzer not supported for ios platform'
|
174
|
+
else
|
175
|
+
unless project.empty?
|
176
|
+
project += '.xcodeproj' unless project.end_with? '.xcodeproj'
|
177
|
+
wrong_path = Dir.glob(root_dir + project).empty?
|
178
|
+
UI.user_error! "Wrong project name '#{project}'. Check extension if you use it." if wrong_path
|
179
|
+
end
|
180
|
+
|
181
|
+
if workspace and !workspace.empty?
|
182
|
+
workspace += '.xcworkspace' unless workspace.end_with? '.xcworkspace'
|
183
|
+
else
|
184
|
+
workspace = project.gsub(".xcodeproj", '') + '.xcworkspace'
|
185
|
+
end
|
186
|
+
wrong_path = Dir.glob(root_dir + workspace).empty?
|
187
|
+
UI.user_error! "Wrong workspace name '#{workspace}'" if wrong_path
|
188
|
+
|
189
|
+
# check targets
|
190
|
+
available_targets = []
|
191
|
+
new_targets = []
|
192
|
+
project_info = Xcodeproj::Project.open(project.to_s)
|
193
|
+
project_info.targets.each do |target|
|
194
|
+
available_targets.push(target.name)
|
195
|
+
end
|
196
|
+
if targets and targets.count > 0
|
197
|
+
error = []
|
198
|
+
targets.each do |currect_target|
|
199
|
+
next if currect_target.tr(' ', '').empty?
|
200
|
+
if available_targets.include? currect_target
|
201
|
+
new_targets.push(currect_target)
|
202
|
+
else
|
203
|
+
error.push(currect_target)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
UI.user_error!("The #{error} targets don't exist in project.") unless error.count == 0
|
207
|
+
end
|
208
|
+
new_targets = available_targets if new_targets.count == 0
|
209
|
+
@checked_xcode_param = true
|
210
|
+
[project, workspace, new_targets]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.description
|
215
|
+
"Runs different Static Analyzers and generate report"
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.authors
|
219
|
+
["olgakn"]
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.return_value
|
223
|
+
# If your method provides a return value, you can describe here what it does
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.details
|
227
|
+
# Optional:
|
228
|
+
"This plugins is the helper for checking code on warnings, copypaste, syntax, etc.\n" \
|
229
|
+
"Each analyzer in this plugin save result status in shared values <NAME>_ANALYZER_STATUS: 0 - code is clear, any other value - code include warnings/errors.\n" \
|
230
|
+
"Also each analyzer save results in separate file: codeAnalysResult_<name of analyzer>.xml"
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.available_options
|
234
|
+
[
|
235
|
+
FastlaneCore::ConfigItem.new(key: :analyzers,
|
236
|
+
env_name: "FL_CSA_RUN_ANALYZERS",
|
237
|
+
description: "List of analysers you want to run. Supported analyzers: #{SUPPORTED_ANALYZER}",
|
238
|
+
optional: false,
|
239
|
+
type: Array,
|
240
|
+
verify_block: proc do |value|
|
241
|
+
UI.message '[!] Will be run all analyzers'.blue if (value and value.empty?) or value[0] == 'all'
|
242
|
+
value.each do |run_analyzer|
|
243
|
+
UI.user_error!("The analyzer '#{run_analyzer}' is not supported. Supported analyzers: #{SUPPORTED_ANALYZER}, 'all'") unless SUPPORTED_ANALYZER.map(&:downcase).include? run_analyzer.downcase or run_analyzer == 'all'
|
244
|
+
end
|
245
|
+
end),
|
246
|
+
FastlaneCore::ConfigItem.new(key: :result_dir,
|
247
|
+
env_name: "CSA_RESULT_DIR_NAME",
|
248
|
+
description: "Directory's name for storing analysis results",
|
249
|
+
optional: true,
|
250
|
+
type: String,
|
251
|
+
default_value: 'artifacts'),
|
252
|
+
# parameters for CPD analyzer
|
253
|
+
FastlaneCore::ConfigItem.new(key: :cpd_tokens,
|
254
|
+
description: "The min number of words in code that is detected as copy paste",
|
255
|
+
optional: true,
|
256
|
+
type: String,
|
257
|
+
default_value: '100'),
|
258
|
+
FastlaneCore::ConfigItem.new(key: :cpd_files_to_inspect,
|
259
|
+
description: "List of files and directories (relative to work directory) to inspect on copy paste",
|
260
|
+
optional: true,
|
261
|
+
type: Array),
|
262
|
+
FastlaneCore::ConfigItem.new(key: :cpd_files_to_exclude,
|
263
|
+
description: "List of files and directories (relative to work directory) not to inspect on copy paste",
|
264
|
+
optional: true,
|
265
|
+
type: Array),
|
266
|
+
FastlaneCore::ConfigItem.new(key: :cpd_language,
|
267
|
+
description: "Language used in files that will be inspected on copy paste.\nSupported analyzers: #{Actions::CpdAnalyzerAction::SUPPORTED_LAN} or don't set if you need any other language",
|
268
|
+
optional: true,
|
269
|
+
type: String,
|
270
|
+
verify_block: proc do |value|
|
271
|
+
UI.user_error!("Language '#{value}' is not supported.\nSupported languages: #{Actions::CpdAnalyzerAction::SUPPORTED_LAN} or empty if you need any other language") unless Actions::CpdAnalyzerAction::SUPPORTED_LAN.map(&:downcase).include? value.downcase or value.empty? or !value
|
272
|
+
end),
|
273
|
+
# parameters for Ruby analyzer
|
274
|
+
FastlaneCore::ConfigItem.new(key: :ruby_files,
|
275
|
+
description: "List of path (relative to work directory) to ruby files to be inspected on warnings & syntax",
|
276
|
+
optional: true,
|
277
|
+
type: Array),
|
278
|
+
# parameters for Warnings analyzer
|
279
|
+
FastlaneCore::ConfigItem.new(key: :xcode_project_name, # required in analyzer
|
280
|
+
description: "Xcode project name in work directory",
|
281
|
+
optional: true,
|
282
|
+
type: String),
|
283
|
+
FastlaneCore::ConfigItem.new(key: :xcode_workspace_name,
|
284
|
+
description: "Xcode workspace name in work directory",
|
285
|
+
optional: true,
|
286
|
+
type: String),
|
287
|
+
FastlaneCore::ConfigItem.new(key: :xcode_targets,
|
288
|
+
description: "List of Xcode targets to inspect",
|
289
|
+
optional: true,
|
290
|
+
type: Array)
|
291
|
+
]
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.output
|
295
|
+
# Define the shared values you are going to provide
|
296
|
+
[
|
297
|
+
['ANALYZER_STATUS', 'Code analysis result (0 - code is clear, any other value - code include warnings/errors/etc.)']
|
298
|
+
]
|
299
|
+
end
|
300
|
+
|
301
|
+
def self.is_supported?(platform)
|
302
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
303
|
+
# See: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
|
304
|
+
#
|
305
|
+
# [:ios, :mac, :android].include?(platform)
|
306
|
+
true
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Actions
|
3
|
+
module SharedValues
|
4
|
+
CPD_ANALYZER_STATUS = :CPD_ANALYZER_STATUS
|
5
|
+
end
|
6
|
+
|
7
|
+
class CpdAnalyzerAction < Action
|
8
|
+
SUPPORTED_LAN = ['python', 'objectivec', 'jsp', 'ecmascript', 'fortran', 'cpp', 'ruby', 'php', 'java', 'matlab', 'scala', 'plsql', 'go', 'cs']
|
9
|
+
|
10
|
+
def self.run(params)
|
11
|
+
UI.header 'CPD analyzer' if Actions::CodeStaticAnalyzerAction.run_from_main_action
|
12
|
+
Actions::CodeStaticAnalyzerAction.is_pmd_installed unless Actions::CodeStaticAnalyzerAction.checked_pmd
|
13
|
+
work_dir = Actions::CodeStaticAnalyzerAction.work_dir
|
14
|
+
|
15
|
+
# checking files for analysing
|
16
|
+
files_to_exclude = params[:cpd_files_to_exclude]
|
17
|
+
files_to_inspect = params[:cpd_files_to_inspect]
|
18
|
+
UI.message '[!] CPD analyzer will be run for all files in work directory'.blue if !files_to_inspect or files_to_inspect.empty?
|
19
|
+
Actions::CodeStaticAnalyzerAction.check_file_exist(work_dir, files_to_exclude, 'cpd_files_to_exclude') if files_to_exclude
|
20
|
+
Actions::CodeStaticAnalyzerAction.check_file_exist(work_dir, files_to_inspect, 'cpd_files_to_inspect') if files_to_inspect
|
21
|
+
|
22
|
+
# prepare script and metadata for saving results
|
23
|
+
result_dir_path = "#{work_dir}#{params[:result_dir]}"
|
24
|
+
FileUtils.mkdir_p(result_dir_path) unless File.exist?(result_dir_path)
|
25
|
+
temp_result_file = "#{result_dir_path}/temp_copypaste.xml"
|
26
|
+
result_file = "#{result_dir_path}/codeAnalysResults_cpd.xml"
|
27
|
+
tokens = params[:tokens]
|
28
|
+
files = Actions::CodeStaticAnalyzerAction.add_root_path(work_dir, files_to_inspect, true)
|
29
|
+
lan = params[:language]
|
30
|
+
exclude_files = Actions::CodeStaticAnalyzerAction.add_root_path(work_dir, files_to_exclude, false)
|
31
|
+
run_script = " pmd cpd --minimum-tokens #{tokens} --files #{files}"
|
32
|
+
run_script += " --exclude #{exclude_files}" unless exclude_files == ''
|
33
|
+
run_script += " --language #{lan}" unless (lan and lan.empty?) or !lan
|
34
|
+
run_script += " --format xml"
|
35
|
+
run_script_path = File.join CodeStaticAnalyzer::ROOT, "assets/run_script.sh"
|
36
|
+
run_script = "#{run_script_path} \"#{run_script}\" '#{temp_result_file}'"
|
37
|
+
# use analyzer
|
38
|
+
Formatter.cpd_format(tokens, lan, exclude_files, temp_result_file, files)
|
39
|
+
FastlaneCore::CommandExecutor.execute(command: run_script.to_s,
|
40
|
+
print_all: false,
|
41
|
+
error: proc do |error_output|
|
42
|
+
# handle error here
|
43
|
+
end)
|
44
|
+
status = $?.exitstatus
|
45
|
+
|
46
|
+
# prepare results
|
47
|
+
if Dir.glob(temp_result_file).empty? or status == 1
|
48
|
+
Actions::CodeStaticAnalyzerAction.start_xml_content unless Actions::CodeStaticAnalyzerAction.run_from_main_action
|
49
|
+
info = (status == 1) ? "CPD return 1: Couldn't understand command line parameters or CPD exited with an exception" : ''
|
50
|
+
Actions::CodeStaticAnalyzerAction.add_xml_content("#{result_dir_path}/", 'Copy paste', temp_result_file, info)
|
51
|
+
Actions::CodeStaticAnalyzerAction.create_analyzers_run_result("#{result_dir_path}/") unless Actions::CodeStaticAnalyzerAction.run_from_main_action
|
52
|
+
status = 43
|
53
|
+
else
|
54
|
+
status = 0 if File.read(temp_result_file).empty?
|
55
|
+
xml_content = JunitParser.parse_xml(temp_result_file)
|
56
|
+
junit_xml = JunitParser.add_testsuite('copypaste', xml_content)
|
57
|
+
JunitParser.create_junit_xml(junit_xml, result_file)
|
58
|
+
end
|
59
|
+
Actions.lane_context[SharedValues::CPD_ANALYZER_STATUS] = status
|
60
|
+
end
|
61
|
+
|
62
|
+
#####################################################
|
63
|
+
# @!group Documentation
|
64
|
+
#####################################################
|
65
|
+
|
66
|
+
def self.description
|
67
|
+
"This analyzer detect copy paste code (it uses PMD CPD)"
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.details
|
71
|
+
# Optional:
|
72
|
+
# this is your chance to provide a more detailed description of this action
|
73
|
+
"Important: install PMD if you want to use copy paste detector\n" \
|
74
|
+
"Important: Always use 'language' parameter except the needed language isn't available in list of supported languages"
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.available_options
|
78
|
+
# Define all options your action supports.
|
79
|
+
[
|
80
|
+
FastlaneCore::ConfigItem.new(key: :result_dir,
|
81
|
+
env_name: "FL_CPD_ANALYZER_RESULT_DIR",
|
82
|
+
description: "Directory's name for storing analysis results",
|
83
|
+
optional: true,
|
84
|
+
type: String,
|
85
|
+
default_value: 'artifacts'),
|
86
|
+
FastlaneCore::ConfigItem.new(key: :tokens,
|
87
|
+
env_name: "FL_CPD_ANALYZER_TOKENS",
|
88
|
+
description: "The min number of words in code that is detected as copy paste",
|
89
|
+
optional: true,
|
90
|
+
type: String,
|
91
|
+
default_value: '100'),
|
92
|
+
FastlaneCore::ConfigItem.new(key: :cpd_files_to_inspect,
|
93
|
+
env_name: "FL_CPD_ANALYZER_FILES_TO_INSPECT",
|
94
|
+
description: "List of files and directories (relative to work directory) to inspect on copy paste",
|
95
|
+
optional: true,
|
96
|
+
type: Array),
|
97
|
+
FastlaneCore::ConfigItem.new(key: :cpd_files_to_exclude,
|
98
|
+
env_name: "FL_CPD_ANALYZER_FILES_NOT_TO_INSPECT",
|
99
|
+
description: "List of files and directories (relative to work directory) not to inspect on copy paste",
|
100
|
+
optional: true,
|
101
|
+
type: Array),
|
102
|
+
FastlaneCore::ConfigItem.new(key: :language,
|
103
|
+
env_name: "FL_CPD_ANALYZER_FILE_LANGUAGE",
|
104
|
+
description: "Language used in files that will be inspected on copy paste.\nSupported analyzers: #{SUPPORTED_LAN} or don't set if you need any other language",
|
105
|
+
optional: true,
|
106
|
+
type: String,
|
107
|
+
verify_block: proc do |value|
|
108
|
+
UI.user_error!("This language is not supported. Supported languages: #{SUPPORTED_LAN} or empty if you need any other language") unless SUPPORTED_LAN.map(&:downcase).include? value.downcase or value.empty? or !value
|
109
|
+
end)
|
110
|
+
]
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.output
|
114
|
+
# Define the shared values you are going to provide
|
115
|
+
[
|
116
|
+
['CPD_ANALYZER_STATUS', 'Copy paste analyzer result status (0 - success, any other value - failed)']
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.return_value
|
121
|
+
# If you method provides a return value, you can describe here what it does
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.authors
|
125
|
+
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
|
126
|
+
["olgakn"]
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.is_supported?(platform)
|
130
|
+
true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|