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.
@@ -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