fastlane-plugin-code_static_analyzer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31ca64424721af47394fb63b3f00532811b84bdf
4
+ data.tar.gz: e12379d050bad5565564d5402ab6b7517b8594a9
5
+ SHA512:
6
+ metadata.gz: b7925823d710984f81d6b483aa41a010325475e68ecf9792fe6ce79a19e70de027170c7950d18565483b6ac16d6f29ef44b4a39b566cc2c687cd4d108c483b3b
7
+ data.tar.gz: 5c3fde6b0c8e7179ca53ea4952ff8f1c7fdddc242d79e6d6a598e85f5c22f46fa7cf879d1f812e73ce096caf7ca1545f7c91ae11d916bdc288d1764fe4edac24
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Olga Kniazska <olgak.kiev@ukr.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,143 @@
1
+ # code_static_analyzer plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-code_static_analyzer)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [fastlane](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-code_static_analyzer`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin code_static_analyzer
11
+ ```
12
+
13
+ ## About code_static_analyzer
14
+
15
+ This plugins runs different Static Analyzers for checking your code on warnings, copypaste, syntax, etc and generate reports.
16
+ Each analyzer in this plugin generate separate report `codeAnalysResult_<name of analyzer>.xml` and
17
+ save result status in shared values `<NAME>_ANALYZER_STATUS`: 0 - code is clear, any other value - code include warnings/errors.
18
+ Finally you can check plugin return value (true='code is clear'/false) to decide what to do next. <br />
19
+ All reports are generated in JUnit format for easier start-up at the CI servers.
20
+
21
+ ## Important
22
+ - You can configure rubocop analyzer by creating configuration file `.rubocop.yml` in your project (more about rubocop configuration http://rubocop.readthedocs.io/en/latest/cops/)
23
+ - All paths should be relative to work directory.
24
+
25
+ ### Specific for copy paste analyzer (CPD)
26
+ - PMD have to be installed on your machine (http://pmd.sourceforge.net/snapshot/usage/installing.html)
27
+ - [!]Pay attention on language parameter: if your code language is available in supported list you have to set this parameter.
28
+
29
+ ## Actions
30
+
31
+ `code_static_analyzer` - runs all configured analyzers together (Copy paste analyzer always runs).<br />
32
+ You may run each analyzer separate:<br />
33
+ `cpd_analyzer` - finds copy paste in code (based on CPD from PMD package) <br />
34
+ `ruby_analyzer` - checks your ruby files. Some offenses can be auto-corrected (if you want to save the changes do it manually) <br />
35
+ `warning_analyzer` - this analyzer uses Xcode built-in analyzer mainly to detect warnings<br />
36
+
37
+ ## Reference and Example
38
+
39
+ ### `code_static_analyzer` (Run all analyzers)
40
+
41
+ ````ruby
42
+ # minimum configuration
43
+ code_static_analyzer(
44
+ analyzers: 'all',
45
+ cpd_language: 'objectivec',
46
+ xcode_project_name: 'path/to/TestProject',
47
+ )
48
+ # full configuration
49
+ code_static_analyzer(
50
+ analyzers: 'all',
51
+ result_dir: 'result directory',
52
+ cpd_tokens: '150',
53
+ cpd_language: 'objectivec',
54
+ cpd_files_to_inspect: 'path/to/myFiles/', # or list %w('path/to/myFiles/' 'path/to/testFiles/')
55
+ cpd_files_to_exclude: 'Pods', # or list %w('Pods' 'path/to/filesNotToInspect/file1.m' 'path/to/filesNotToInspect/in/dir')
56
+ xcode_project_name: 'path/to/TestProject',
57
+ xcode_workspace_name: 'path/to/testWorkspace',
58
+ xcode_targets: ['TPClientTarget','TPServerTarget'],
59
+ ruby_files: 'fastlane/Fastfile'
60
+ )
61
+ ````
62
+ Parameter | Description
63
+ --------- | -----------
64
+ `analyzers` | List of analysers you want to run. Supported analyzers: "xcodeWar", "rubocop", "CPD", "all"
65
+ `result_dir` | *(optional)* Directory's name for storing analysis results.
66
+ `cpd_tokens` | *(optional)* The min number of words in code that is detected as copy paste.<br />Default value: 100
67
+ `cpd_language` | *(optional)* Language used in files that will be inspected on copy paste.<br />Supported analyzers: ['python', 'objectivec', 'jsp', 'ecmascript', 'fortran', 'cpp', 'ruby', 'php', 'java', 'matlab', 'scala', 'plsql', 'go', 'cs']. If you need any other language just don't set this parameter.
68
+ `cpd_files_to_inspect` | *(optional)* List of paths (relative to work directory) to files/directories to be inspected on copy paste.
69
+ `cpd_files_to_exclude` | *(optional)* List of paths (relative to work directory) to files/directories not to be inspected on copy paste
70
+ `xcode_project_name` | *(required if use warning analyzer)* Xcode project name in work directory
71
+ `xcode_workspace_name`| *(optional)* Xcode workspace name in work directory. Set it if you use different project & workspace names
72
+ `xcode_targets` | *(optional)* List of Xcode targets to inspect. By default used all targets which are available in project
73
+ `ruby_files` | *(optional)* List of paths to ruby files to be inspected
74
+
75
+ ### `code_static_analyzer` other examples (full configuration):
76
+ CPD:
77
+ ````ruby
78
+ code_static_analyzer(
79
+ analyzers: 'cpd',
80
+ result_dir: 'result directory',
81
+ cpd_tokens: '150',
82
+ cpd_language: 'objectivec',
83
+ cpd_files_to_inspect: %w('path/to/myFiles/' 'path/to/testFiles/'),
84
+ cpd_files_to_exclude: %w('Pods' 'ThirdParty')
85
+ )
86
+ ````
87
+ CPD + ruby:
88
+ ````ruby
89
+ code_static_analyzer(
90
+ analyzers: 'rubocop',
91
+ result_dir: 'result directory',
92
+ cpd_tokens: '150',
93
+ cpd_language: 'objectivec',
94
+ cpd_files_to_inspect: %w('path/to/myFiles/' 'path/to/testFiles/'),
95
+ cpd_files_to_exclude: %w('Pods' 'ThirdParty'),
96
+ ruby_files: 'fastlane/Fastfile'
97
+ )
98
+ ````
99
+ CPD + Xcode project warnings:
100
+ ````ruby
101
+ code_static_analyzer(
102
+ analyzers: 'xcodewar',
103
+ result_dir: 'result directory',
104
+ cpd_tokens: '150',
105
+ cpd_language: 'objectivec',
106
+ cpd_files_to_inspect: %w('path/to/myFiles/' 'path/to/testFiles/'),
107
+ cpd_files_to_exclude: %w('Pods' 'ThirdParty'),
108
+ xcode_project_name: 'path/to/TestProject',
109
+ xcode_workspace_name: 'path/to/testWorkspace',
110
+ xcode_targets: ['TPClientTarget','TPServerTarget'],
111
+ )
112
+ ````
113
+
114
+ ## Run tests for this plugin
115
+
116
+ To run both the tests, and code style validation, run
117
+
118
+ ```
119
+ rake
120
+ ```
121
+
122
+ To automatically fix many of the styling issues, use
123
+ ```
124
+ rubocop -a
125
+ ```
126
+
127
+ ## Issues and Feedback
128
+
129
+ - In some cases CPD can't recognize patterns in file/dir paths like `path/to/files/*.m`
130
+ (about path you may read in CPD documentation: http://pmd.sourceforge.net/snapshot/usage/cpd-usage.html)<br />
131
+ For any other issues and feedback about this plugin, please submit it to this repository.
132
+
133
+ ## Troubleshooting
134
+
135
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
136
+
137
+ ## Using `fastlane` Plugins
138
+
139
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
140
+
141
+ ## About `fastlane`
142
+
143
+ `fastlane` is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,27 @@
1
+ #!/bin/bash -o pipefail
2
+ #!/bin/sh -e
3
+ # code_analys.sh
4
+ # @desc Detect code warnings/errors by using static analyzer build in Xcode.
5
+ # @usage
6
+ # 1. Income parameters
7
+ # WORKSPACE_PROJECT - name of xcode project or workspace (.xcodeproj / .xcworkspace)
8
+ # BUILD_LANE - name of project target
9
+ # LOG - path-name of .log file for temporary usage to store full output of Xcode command
10
+ # IN_WORKSPACE - true if WORKSPACE_PROJECT=.xcworkspace
11
+
12
+ WORKSPACE_PROJECT=$1
13
+ BUILD_LANE=$2
14
+ LOG=$3
15
+ IN_WORKSPACE=$4
16
+
17
+ #detect warnings
18
+ #analyze code (build in xcode tools)
19
+ if $IN_WORKSPACE; then
20
+ xcodebuild -scheme $BUILD_LANE -workspace $WORKSPACE_PROJECT clean analyze |
21
+ tee "$LOG" |
22
+ xcpretty
23
+ else
24
+ xcodebuild -scheme $BUILD_LANE -project $WORKSPACE_PROJECT clean analyze |
25
+ tee "$LOG" |
26
+ xcpretty
27
+ fi
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env ruby
2
+ # output_looking.rb
3
+ # @desc Tools for preparing better looking running output
4
+ # @usage
5
+ # in needed file paste string: require './path-to-file/output_looking.rb
6
+
7
+ # Use to prepare formatted output
8
+ module Formatter
9
+ def self.return_status(mystatus)
10
+ puts light_blue(">>> Exit command status: #{mystatus}")
11
+ end
12
+
13
+ def self.xcode_format(scheme)
14
+ puts ">>> Running Xcode analyze command... on #{scheme}..."
15
+ end
16
+
17
+ def self.cpd_format(tokens, language, exclude, result_file, inspect)
18
+ puts "files : #{inspect}"
19
+ puts "min_tokens : #{tokens}"
20
+ puts "language : #{language}"
21
+ puts "exclude_files : #{exclude}"
22
+ puts 'format : xml'
23
+ puts "output_file : #{result_file}"
24
+ end
25
+
26
+ # String colorization
27
+ # call UI.message Actions::FormatterAction.light_blue(text)
28
+ def self.light_blue(mytext)
29
+ "\e[36m#{mytext}\e[0m"
30
+ end
31
+ end
@@ -0,0 +1,225 @@
1
+ #! /usr/bin/env ruby
2
+ # parser.sh
3
+ # @desc Parser
4
+ # @usage
5
+ # 1. Parser 1. Xcode analyze result (.log)
6
+ # 2. Parser 2. Rubocop result (.json)
7
+ # 3. Parser 3. CPD result (.xml)
8
+
9
+ require 'crack'
10
+
11
+ module JunitParser
12
+ #####################################################
13
+ # ================= For all parsers =================
14
+ #####################################################
15
+
16
+ def self.create_xml(xml_data_custom, result_file_name)
17
+ xml_data = '<?xml version="1.0" encoding="UTF-8"?>'
18
+ xml_data += xml_data_custom
19
+ File.open(result_file_name, 'w') do |f|
20
+ f.write(xml_data)
21
+ end
22
+ end
23
+
24
+ def self.create_testsuites(testsuites)
25
+ "#{xml_level(0)}<testsuites>#{testsuites}#{xml_level(0)}</testsuites>"
26
+ end
27
+
28
+ def self.add_testsuite(name, testcases)
29
+ "#{xml_level(1)}<testsuite name='#{name}'>" \
30
+ "#{testcases}" \
31
+ "#{xml_level(1)}</testsuite>"
32
+ end
33
+
34
+ def self.add_failed_testcase(name, failures)
35
+ "#{xml_level(2)}<testcase name='#{name}'>" \
36
+ "#{failures}#{xml_level(2)}</testcase>"
37
+ end
38
+
39
+ def self.add_success_testcase(name)
40
+ "#{xml_level(2)}<testcase name='#{name}' status='success'/>"
41
+ end
42
+
43
+ def self.add_failure(message, type, text)
44
+ "#{xml_level(3)}<failure #{insert_attribute('type', type)} status='failed' " \
45
+ "#{insert_attribute('message', message)}>" \
46
+ "#{text}" \
47
+ "#{xml_level(3)}</failure>"
48
+ end
49
+
50
+ def self.add_properties(property_array, value_array)
51
+ properties = "#{xml_level(2)}<properties>"
52
+ property_array.each_with_index do |property, index|
53
+ value = value_array[index]
54
+ unless value.nil?
55
+ properties += "#{xml_level(3)}<property name='#{property}' value='#{value}' />"
56
+ end
57
+ end
58
+ properties += "#{xml_level(2)}</properties>"
59
+ end
60
+
61
+ def self.construct_failure_mes(attributes, values)
62
+ properties = xml_level(0).to_s
63
+ attributes.each_with_index do |property, index|
64
+ value = values[index]
65
+ properties += format("#{xml_level(4)}%-18s: %s", property, value) unless value.nil?
66
+ end
67
+ properties
68
+ end
69
+
70
+ def self.insert_attribute(attribute, value)
71
+ value == '' ? '' : "#{attribute}='#{value}'"
72
+ end
73
+
74
+ def self.add_code(codefragment)
75
+ "<![CDATA[#{codefragment}]]>"
76
+ end
77
+
78
+ def self.get_failure_type(str)
79
+ failure_type = str[/\[(.*?)\]/, 1]
80
+ failure_type = '-W' if failure_type.nil?
81
+ failure_type
82
+ end
83
+
84
+ def self.xml_level(level)
85
+ levelstr = "\n"
86
+ i = 1
87
+ while i < level
88
+ levelstr += "\s\s"
89
+ i += 1
90
+ end
91
+ levelstr
92
+ end
93
+
94
+ # create root xml content
95
+ def self.create_junit_xml(testsuite, result_file_name)
96
+ full_data = create_testsuites(testsuite)
97
+ create_xml(full_data, result_file_name)
98
+ end
99
+
100
+ #####################################################
101
+ # ============== Xcode-log Parser ================
102
+ #####################################################
103
+
104
+ def self.parse_xcode_log(file, project, is_warn)
105
+ if is_warn
106
+ error_text = ''
107
+ File.open(file).each do |line|
108
+ if line =~ /warning:|error:/
109
+ warning_params = line.split(':')
110
+ if warning_params.count == 5
111
+ error_text += construct_failure_mes(
112
+ ['Error ClassType', 'Error in File', 'Error Line', 'Error Message'],
113
+ [get_failure_type(warning_params[4]), warning_params[0].tr('<', '').tr('>', ''),
114
+ "#{warning_params[1]}:#{warning_params[2]}", warning_params[4].tr("\n", '')]
115
+ )
116
+ else
117
+ error_text += construct_failure_mes(
118
+ ['Error ClassType', 'Error Message'],
119
+ ['-W', line.tr("\n", '')]
120
+ )
121
+ end
122
+ end
123
+ next unless line =~ /BCEROR/
124
+ error_text += construct_failure_mes(['Error ClassType', 'Error in File', 'Error Message'],
125
+ [get_failure_type(line), 'project configuration',
126
+ line.tr("\n", '')])
127
+ end
128
+ failures = add_failure('', '', error_text)
129
+ add_failed_testcase(project, failures)
130
+ else
131
+ add_success_testcase(project)
132
+ end
133
+ end
134
+
135
+ #####################################################
136
+ # ============== Rubocop-json Parser ================
137
+ #####################################################
138
+
139
+ def self.parse_json(file)
140
+ data_read = File.read(file)
141
+ data_hash = Crack::JSON.parse(data_read)
142
+
143
+ keys = data_hash['metadata'].keys.zip(data_hash['summary'].keys).flatten.compact
144
+ values = data_hash['metadata'].values.zip(data_hash['summary'].values).flatten.compact
145
+ properties = add_properties(keys, values)
146
+
147
+ testcase = parse_main_json(data_hash)
148
+
149
+ properties + testcase
150
+ end
151
+
152
+ # create main xml content
153
+ def self.parse_main_json(data_hash)
154
+ xml = ''
155
+ data_hash['files'].each do |inspected_file|
156
+ error_text = ''
157
+ errors = inspected_file['offenses']
158
+ if errors.empty?
159
+ xml += add_success_testcase((inspected_file['path']).to_s)
160
+ else
161
+ errors.each do |error|
162
+ error_text += construct_failure_mes(
163
+ ['Error isCorrected', 'Error ClassType', 'Error Line', 'Error Message'],
164
+ [error['corrected'], "#{error['cop_name']} (#{error['severity']})",
165
+ parse_location(error['location']), error['message'].tr("\n", '')]
166
+ )
167
+ end
168
+ # TODO: corrected:6 failded:0 (if needed this info)
169
+ failures = add_failure('lineformat=line:column:length', '', error_text)
170
+ xml += add_failed_testcase((inspected_file['path']).to_s, failures)
171
+ end
172
+ end
173
+ xml
174
+ end
175
+
176
+ def self.parse_location(location)
177
+ "#{location['line']}:#{location['column']}:#{location['length']}"
178
+ end
179
+
180
+ #####################################################
181
+ # ================= CPD-xml Parser ==================
182
+ #####################################################
183
+
184
+ def self.parse_xml(file)
185
+ data_read = File.read(file)
186
+ data_hash = Crack::XML.parse(data_read)
187
+
188
+ if data_hash.empty? or data_hash['pmd_cpd']==nil
189
+ puts 'empty data_hash'
190
+ add_success_testcase('casino duplications')
191
+ else
192
+ parse_code_duplications(data_hash)
193
+ end
194
+ end
195
+
196
+ def self.parse_code_duplications(data_hash)
197
+ xml = ''
198
+ duplications = data_hash['pmd_cpd']['duplication']
199
+ if duplications.kind_of?(Array)
200
+ index = 1
201
+ duplications.each do |error|
202
+ parsed_files = parse_inspected_files(error['file'])
203
+ failure = add_failure("lines:#{error['lines']} tokens:#{error['tokens']} #{xml_level(3)}files:#{parsed_files}", '', "\n#{add_code(error['codefragment'])}")
204
+ xml += add_failed_testcase("duplication #{index}", failure)
205
+ index += 1
206
+ end
207
+ else
208
+ parsed_files = parse_inspected_files(duplications['file'])
209
+ failure = add_failure("lines:#{duplications['lines']} tokens:#{duplications['tokens']} #{xml_level(3)}files:#{parsed_files}", '',
210
+ "\n #{add_code(duplications['codefragment'])}")
211
+ xml += add_failed_testcase('single duplication', failure)
212
+ end
213
+ xml
214
+ end
215
+
216
+ def self.parse_inspected_files(file_list)
217
+ index = 1
218
+ file_list_info = []
219
+ file_list.each do |file|
220
+ file_list_info.push("File #{index}: #{file['path']}::#{file['line']}")
221
+ index += 1
222
+ end
223
+ file_list_info
224
+ end
225
+ end