flutter_rb 0.8.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9b9c4ba6b6d7ede4690bf5d4c56db1690eebd150aed2280f2921d0ee42cf3dee
4
+ data.tar.gz: dc1abf19802d39f9448c79421a3b9086b460381a3de664d592e2f1df385c6f80
5
+ SHA512:
6
+ metadata.gz: bd273e042215353d3b5ebfdcf058d303533e4495a1374642cf4a3202d321405b4fdf70a5c7100653921ae8f7e0751a41d4beb097ab2237379fb873abaad1eb02
7
+ data.tar.gz: ea9a7665e9b66602a15aaab0aa71730069bd01473df6302fdd7b19f5b2aff1c9d1f723b25a7bff4803af1ca8cdc7e6c6c4f57242b53d3447a0a474a2e3a74555
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2020-2022 Artem Fomchenkov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ <img src="media/logo/ic_lib.png" height="100px">
2
+
3
+ # flutter_rb
4
+
5
+ [![GitHubActions](https://github.com/fartem/flutter_rb/workflows/Build/badge.svg)](https://github.com/fartem/flutter_rb/actions?query=workflow%3ARuby)
6
+ [![Codebeat](https://codebeat.co/badges/9bb32e28-ca86-4cdc-ba66-bda7f989979a)](https://codebeat.co/projects/github-com-fartem-flutter_rb-master)
7
+ [![Coveralls](https://coveralls.io/repos/github/fartem/flutter_rb/badge.svg?branch=master)](https://coveralls.io/github/fartem/flutter_rb?branch=master)
8
+
9
+ ## About
10
+
11
+ A tool for checking a Flutter plugin structure.
12
+
13
+ ### Checks
14
+
15
+ #### Levels
16
+
17
+ Each issue has a `level` parameter that describes his significate level.
18
+
19
+ | Level | Description |
20
+ | --- | --- |
21
+ | `NORMAL` | Issue was not found |
22
+ | `WARNING` | Issue is not serious and cannot break build |
23
+ | `ERROR` | Issue is critical and can break build |
24
+
25
+ #### Flutter
26
+
27
+ | Check | Description | Level |
28
+ | --- | --- | --- |
29
+ | `PluginDirectoriesCheck` | Check plugin directories structure in pubspec file. Example: if a Flutter plugin has only Android specific code but not contains iOS folder with description, then iOS build fails | `ERROR` |
30
+ | `PluginPubspecNameCheck` | Check plugin name in pubspec file. Exists or not | `ERROR` |
31
+ | `PluginPubspecDescriptionCheck` | Check plugin description in pubspec file. Exists or not | `WARNING` |
32
+ | `PluginPubspecVersionCheck` | Check plugin version in pubspec. Exists or not | `ERROR` |
33
+ | `PluginPubspecAuthorCheck` | Check plugin author in pubspec. Exists or not. `author` section deprecated in `pubspec.yaml` | `WARNING` |
34
+ | `PluginPubspecHomepageCheck` | Check plugin homepage in pubspec. Exists or not | `ERROR` |
35
+ | `PluginPubspecEffectiveDartCheck` | Check Flutter plugin Effective Dart depencency in pubspec file. Exists or not | `ERROR` |
36
+
37
+ #### Android
38
+
39
+ | Check | Description | Level |
40
+ | --- | --- | --- |
41
+ | `PluginGradleAndroidPackageCheck` | Validate that \android\ package not exists in Gradle project config (build.gradle file) | `ERROR` |
42
+ | `PluginGradleVersionCheck` | Check plugin version in Gradle project config (build.gradle file). Version must be the same as plugin version in pubspec file | `WARNING` |
43
+
44
+ #### iOS
45
+
46
+ | Check | Description | Level |
47
+ | --- | --- | --- |
48
+ | `PluginPodspecNameCheck` | Check plugin name in podspec file. Exists or not | `WARNING` |
49
+ | `PluginPodspecVersionCheck` | Check plugin version in podspec file. Exists or not | `WARNING` |
50
+ | `PluginPodspecAuthorsCheck` | Check plugin's authors in podspec file. Exists or not | `ERROR` |
51
+ | `PluginPodspecSourceCheck` | Check plugin iOS source path in podspec file. If Flutter plugin cannot contains iOS specific code, source path must be `'.'` | `ERROR` |
52
+
53
+ ## How to use
54
+
55
+ ### Android
56
+
57
+ You should add [flutter-rb-gradle-plugin](https://github.com/fartem/flutter-rb-gradle-plugin) to Android side of your plugin.
58
+
59
+ ### As local installed gem
60
+
61
+ Build gem from sources:
62
+
63
+ ```shell
64
+ gem build flutter_rb.gemspec
65
+ ```
66
+
67
+ Install gem:
68
+
69
+ ```shell
70
+ gem i flutter_rb
71
+ ```
72
+
73
+ Then run from a Flutter plugin's project folder:
74
+
75
+ ```shell
76
+ frb
77
+ ```
78
+
79
+ ### As local executable
80
+
81
+ Add `project_folder/bin` (where `project_folder` is path to project on your machine) to `PATH` variable in your environment. Then updated environment and run from a Flutter plugin's project folder:
82
+
83
+ ```shell
84
+ local_frb
85
+ ```
86
+
87
+ ### Arguments
88
+
89
+ | Argument | Description |
90
+ | --- | --- |
91
+ | `--help` | Print help info |
92
+ | `--checkstyle-report` | Generate report in Checkstyle format |
93
+
94
+
95
+ ### Configuration
96
+
97
+ Add `.flutter_rb.yaml` to root of a project for select checks that you are want to execute:
98
+
99
+ ```yaml
100
+ include:
101
+ flutter:
102
+ - check1
103
+ - check2
104
+ - check3
105
+ android:
106
+ - check1
107
+ - check2
108
+ ios:
109
+ - check1
110
+ - check2
111
+
112
+ ```
113
+
114
+ ### Output report
115
+
116
+ Tool can make report in Checkstyle format. To enable this feature, pass `--checkstyle-report` as an CLI argument. The report file name is `frb-checkstyle-report.xml`.
117
+
118
+ ## How to contribute
119
+
120
+ Read [Commit Convention](https://github.com/fartem/repository-rules/blob/master/commit-convention/COMMIT_CONVENTION.md). Make sure your build is green before you contribute your pull request. Then:
121
+
122
+ ```shell
123
+ bundle exec rake
124
+ ```
125
+
126
+ If you don't see any error messages, submit your pull request.
127
+
128
+ ## Contributors
129
+
130
+ - [@fartem](https://github.com/fartem) as Artem Fomchenkov
data/bin/frb ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'flutter_rb'
4
+ require 'colorize'
5
+
6
+ def light_blue_text(text)
7
+ text.colorize(:light_blue)
8
+ end
9
+
10
+ if ARGV.include?('--help')
11
+ puts "
12
+ Available aruments:
13
+ * #{light_blue_text('--help')}: print help info
14
+ * #{light_blue_text('--checkstyle-report')}: generate report in Checkstyle format
15
+ "
16
+ else
17
+ flutter_rb = FlutterRb::FlutterRb.new
18
+ flutter_rb.start(Dir.pwd, ARGV.include?('--checkstyle-report'))
19
+ end
@@ -0,0 +1,90 @@
1
+ require 'nokogiri'
2
+
3
+ # Module with classes for creating reports in Checkstyle format
4
+ module CheckstyleReport
5
+ # Class for create report in Checkstyle format
6
+ class CheckstyleReport
7
+ def initialize(path, report_filename, checks)
8
+ @path = path
9
+ @report_filename = report_filename
10
+ @checks = checks
11
+ end
12
+
13
+ def create_report
14
+ checkstyle_files = sort_checks(@checks)
15
+ report = Nokogiri::XML::Builder.new do |xml|
16
+ xml.checkstyle(version: '8.38') do
17
+ checkstyle_files
18
+ .map { |file, errors| CheckstyleFile.new(file, errors) }
19
+ .each { |file| write_file(xml, file) }
20
+ end
21
+ end
22
+ File.open("#{@path}/#{@report_filename}.xml", 'w') { |file| file.write(report.to_xml) }
23
+ end
24
+
25
+ def sort_checks(checks)
26
+ checkstyle_files = {}
27
+ checks.each do |check|
28
+ checkstyle_file = checkstyle_files[check.source]
29
+ checkstyle_files[check.source] = [] if checkstyle_file.nil?
30
+ checkstyle_files[check.source] += [check] if check.saverity != CheckstyleError::SAVERITY_NORMAL
31
+ end
32
+ checkstyle_files
33
+ end
34
+
35
+ def write_file(xml, checkstyle_file)
36
+ xml.file(name: checkstyle_file.file) do
37
+ checkstyle_file.errors.each do |error|
38
+ write_error(xml, error)
39
+ end
40
+ end
41
+ end
42
+
43
+ def write_error(xml, error)
44
+ xml.error(
45
+ line: error.line,
46
+ column: error.column,
47
+ saverity: error.saverity,
48
+ message: error.message,
49
+ source: error.source
50
+ )
51
+ end
52
+ end
53
+
54
+ # File representation for Checkstyle format
55
+ class CheckstyleFile
56
+ def initialize(file, errors)
57
+ @file = file
58
+ @errors = errors
59
+ end
60
+
61
+ attr_reader :file, :errors
62
+ end
63
+
64
+ # Checkstyle error representation
65
+ class CheckstyleError
66
+ SAVERITY_NORMAL = 'normal'.freeze
67
+ SAVERITY_WARNING = 'warning'.freeze
68
+ SAVERITY_ERROR = 'error'.freeze
69
+
70
+ # rubocop:disable Metrics/ParameterLists
71
+ def initialize(
72
+ saverity,
73
+ message,
74
+ source,
75
+ line,
76
+ column,
77
+ name
78
+ )
79
+ @saverity = saverity
80
+ @message = message
81
+ @source = source
82
+ @line = line
83
+ @column = column
84
+ @name = name
85
+ end
86
+ # rubocop:enable Metrics/ParameterLists
87
+
88
+ attr_reader :saverity, :message, :source, :line, :column, :name
89
+ end
90
+ end
@@ -0,0 +1,24 @@
1
+ module FlutterRb
2
+ # Base class for all checks
3
+ # Class provides default methods structure
4
+ # All methods using for create reports
5
+ class Check
6
+ UNIMPLEMENTATION_ERROR = 'Error: missing method'.freeze
7
+
8
+ def name
9
+ raise UNIMPLEMENTATION_ERROR
10
+ end
11
+
12
+ def summary
13
+ raise UNIMPLEMENTATION_ERROR
14
+ end
15
+
16
+ def description
17
+ 'No provided'
18
+ end
19
+
20
+ def check
21
+ raise UNIMPLEMENTATION_ERROR
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'check'
2
+ require_relative '../report/check_report'
3
+
4
+ module FlutterRb
5
+ # Check plugin directories structure.
6
+ # Example: if a Flutter plugin has only Android specific code
7
+ # but not contains iOS folder with description, then iOS build fails
8
+ class PluginDirectoriesCheck < Check
9
+ def name
10
+ 'PluginDirectoriesCheck'
11
+ end
12
+
13
+ def summary
14
+ 'Validate Flutter plugin structure'
15
+ end
16
+
17
+ def description
18
+ 'Check plugin directories structure in pubspec file'
19
+ end
20
+
21
+ def check(project)
22
+ android_exists = !project.android_folder.nil?
23
+ ios_exists = !project.ios_folder.nil?
24
+ check_result = android_exists && ios_exists || !android_exists && !ios_exists
25
+ CheckReport.new(
26
+ name,
27
+ check_result ? CheckReportStatus::NORMAL : CheckReportStatus::ERROR,
28
+ description,
29
+ project.path
30
+ )
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,57 @@
1
+ require_relative './check'
2
+ require_relative '../report/check_report'
3
+
4
+ module FlutterRb
5
+ # Check 'android; import not exists in Gradle project config (build.gradle file)
6
+ class PluginGradleAndroidPackageCheck < Check
7
+ def name
8
+ 'PluginGradleAndroidPackageCheck'
9
+ end
10
+
11
+ def summary
12
+ 'Validate that \android\ package not exists in build.gradle config'
13
+ end
14
+
15
+ def description
16
+ 'Validate that \android\ package not exists in Gradle project config (build.gradle file)'
17
+ end
18
+
19
+ def check(project)
20
+ gradle = project.android_folder.gradle
21
+ import_exist = File.readlines("#{gradle.path}/build.gradle").grep(/package android/).size.positive?
22
+ CheckReport.new(
23
+ name,
24
+ import_exist ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
25
+ description,
26
+ gradle.path
27
+ )
28
+ end
29
+ end
30
+
31
+ # Check Flutter plugin version in Gradle project config (build.gradle file)
32
+ class PluginGradleVersionCheck < Check
33
+ def name
34
+ 'PluginGradleVersionCheck'
35
+ end
36
+
37
+ def summary
38
+ 'Validate Flutter plugin\s version in build.gradle file'
39
+ end
40
+
41
+ def description
42
+ 'Check plugin version in Gradle project config (build.gradle file)'
43
+ end
44
+
45
+ def check(project)
46
+ version_in_pubspec = project.pubspec.pubspec_info.version
47
+ gradle = project.android_folder.gradle
48
+ version_in_gradle = gradle.version
49
+ CheckReport.new(
50
+ name,
51
+ version_in_pubspec == version_in_gradle ? CheckReportStatus::NORMAL : CheckReportStatus::WARNING,
52
+ description,
53
+ gradle.path
54
+ )
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,109 @@
1
+ require_relative 'check'
2
+ require_relative '../report/check_report'
3
+
4
+ module FlutterRb
5
+ # Base class for all info parameters in Flutter plugin podspec file
6
+ class PluginPodspecCheck < Check
7
+ def name
8
+ "PluginPodspec#{podspec_parameter.capitalize}Check"
9
+ end
10
+
11
+ def podspec_parameter
12
+ UNIMPLEMENTATION_ERROR
13
+ end
14
+
15
+ def summary
16
+ "Validate Flutter plugin's #{podspec_parameter} in podspec file"
17
+ end
18
+ end
19
+
20
+ # Check Flutter plugin name in podspec file. Exists or not
21
+ class PluginPodspecNameCheck < PluginPodspecCheck
22
+ def podspec_parameter
23
+ 'name'
24
+ end
25
+
26
+ def check(project)
27
+ name_in_pubspec = project.pubspec.pubspec_info.name
28
+ podspec = project.ios_folder.podspec
29
+ name_in_podspec = podspec.name
30
+ CheckReport.new(
31
+ name,
32
+ name_in_pubspec == name_in_podspec ? CheckReportStatus::NORMAL : CheckReportStatus::WARNING,
33
+ description,
34
+ podspec.path
35
+ )
36
+ end
37
+
38
+ def description
39
+ 'Check plugin name in podspec file'
40
+ end
41
+ end
42
+
43
+ # Check Flutter plugin version in podspec file. Exists or not
44
+ class PluginPodspecVersionCheck < PluginPodspecCheck
45
+ def podspec_parameter
46
+ 'version'
47
+ end
48
+
49
+ def check(project)
50
+ version_in_pubspec = project.pubspec.pubspec_info.version
51
+ podspec = project.ios_folder.podspec
52
+ version_in_podspec = podspec.version
53
+ CheckReport.new(
54
+ name,
55
+ version_in_pubspec == version_in_podspec ? CheckReportStatus::NORMAL : CheckReportStatus::WARNING,
56
+ description,
57
+ podspec.path
58
+ )
59
+ end
60
+
61
+ def description
62
+ 'Check plugin version in podspec file'
63
+ end
64
+ end
65
+
66
+ # Check Flutter plugin's authors. Exists or not
67
+ class PluginPodspecAuthorsCheck < PluginPodspecCheck
68
+ def podspec_parameter
69
+ 'authors'
70
+ end
71
+
72
+ def check(project)
73
+ podspec = project.ios_folder.podspec
74
+ author_exists = !podspec.authors.nil?
75
+ CheckReport.new(
76
+ name,
77
+ author_exists ? CheckReportStatus::NORMAL : CheckReportStatus::ERROR,
78
+ description,
79
+ podspec.path
80
+ )
81
+ end
82
+
83
+ def description
84
+ "Check plugin's authors in podspec file"
85
+ end
86
+ end
87
+
88
+ # Check plugin iOS source path in podspec file.
89
+ # If Flutter plugin cannot contains iOS specific code, source path must be '.'
90
+ class PluginPodspecSourceCheck < PluginPodspecCheck
91
+ def podspec_parameter
92
+ 'source'
93
+ end
94
+
95
+ def check(project)
96
+ podspec = project.ios_folder.podspec
97
+ CheckReport.new(
98
+ name,
99
+ podspec.source.nil? ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
100
+ description,
101
+ podspec.path
102
+ )
103
+ end
104
+
105
+ def description
106
+ 'Check plugin iOS source path in podspec file'
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,152 @@
1
+ require_relative 'check'
2
+ require_relative '../report/check_report'
3
+
4
+ module FlutterRb
5
+ # Base class for all info parameters in Flutter plugin pubspec.yaml file
6
+ class PluginPubspecCheck < Check
7
+ def name
8
+ "PluginPubspec#{pubspec_parameter.capitalize}Check"
9
+ end
10
+
11
+ def pubspec_parameter
12
+ raise UNIMPLEMENTATION_ERROR
13
+ end
14
+
15
+ def summary
16
+ "Validate Flutter plugin's #{pubspec_parameter} in pubspec.yaml"
17
+ end
18
+ end
19
+
20
+ # Check Flutter plugin name in podspec file. Exists or not
21
+ class PluginPubspecNameCheck < PluginPubspecCheck
22
+ def pubspec_parameter
23
+ 'name'
24
+ end
25
+
26
+ def check(project)
27
+ pubspec = project.pubspec
28
+ CheckReport.new(
29
+ name,
30
+ pubspec.pubspec_info.name.nil? ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
31
+ description,
32
+ pubspec.path
33
+ )
34
+ end
35
+
36
+ def description
37
+ 'Check plugin name in pubspec file'
38
+ end
39
+ end
40
+
41
+ # Check Flutter plugin description in pubspec file. Exists or not
42
+ class PluginPubspecDescriptionCheck < PluginPubspecCheck
43
+ def pubspec_parameter
44
+ 'description'
45
+ end
46
+
47
+ def check(project)
48
+ pubspec = project.pubspec
49
+ CheckReport.new(
50
+ name,
51
+ pubspec.pubspec_info.description.nil? ? CheckReportStatus::WARNING : CheckReportStatus::NORMAL,
52
+ description,
53
+ pubspec.path
54
+ )
55
+ end
56
+
57
+ def description
58
+ 'Check plugin description in pubspec file'
59
+ end
60
+ end
61
+
62
+ # Check Flutter plugin version in pubspec file. Exists or not
63
+ class PluginPubspecVersionCheck < PluginPubspecCheck
64
+ def pubspec_parameter
65
+ 'version'
66
+ end
67
+
68
+ def check(project)
69
+ pubspec = project.pubspec
70
+ CheckReport.new(
71
+ name,
72
+ pubspec.pubspec_info.version.nil? ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
73
+ description,
74
+ pubspec.path
75
+ )
76
+ end
77
+
78
+ def description
79
+ 'Check plugin version in pubspec'
80
+ end
81
+ end
82
+
83
+ # Check Flutter plugin author in pubspec file. Exists or not
84
+ class PluginPubspecAuthorCheck < PluginPubspecCheck
85
+ def pubspec_parameter
86
+ 'author'
87
+ end
88
+
89
+ def check(project)
90
+ pubspec = project.pubspec
91
+ CheckReport.new(
92
+ name,
93
+ pubspec.pubspec_info.author.nil? ? CheckReportStatus::NORMAL : CheckReportStatus::WARNING,
94
+ description,
95
+ pubspec.path
96
+ )
97
+ end
98
+
99
+ def description
100
+ 'Check plugin author in pubspec'
101
+ end
102
+ end
103
+
104
+ # Check Flutter plugin homepage in pubspec file. Exists or not
105
+ class PluginPubspecHomepageCheck < PluginPubspecCheck
106
+ def pubspec_parameter
107
+ 'homepage'
108
+ end
109
+
110
+ def check(project)
111
+ pubspec = project.pubspec
112
+ CheckReport.new(
113
+ name,
114
+ pubspec.pubspec_info.homepage.nil? ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
115
+ description,
116
+ pubspec.path
117
+ )
118
+ end
119
+
120
+ def description
121
+ 'Check plugin homepage in pubspec'
122
+ end
123
+ end
124
+
125
+ # Check Flutter plugin Effective Dart depencency in pubspec file. Exists or not
126
+ class PluginPubspecEffectiveDartCheck < Check
127
+ def name
128
+ 'PluginPubspecEffectiveDartCheck'
129
+ end
130
+
131
+ def summary
132
+ 'Validate Flutter plugin\'s Effective Dart rules implementation in pubspec.yaml'
133
+ end
134
+
135
+ def check(project)
136
+ pubspec = project.pubspec
137
+ effective_dart = pubspec.dev_dependencies&.detect do |dev_dependency|
138
+ dev_dependency.name == 'effective_dart'
139
+ end
140
+ CheckReport.new(
141
+ name,
142
+ effective_dart.nil? ? CheckReportStatus::ERROR : CheckReportStatus::NORMAL,
143
+ description,
144
+ pubspec.path
145
+ )
146
+ end
147
+
148
+ def description
149
+ 'Check Flutter plugin Effective Dart depencency in pubspec file'
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,16 @@
1
+ module FlutterRb
2
+ # FlutterRb configuration representation from config in Flutter plugin
3
+ class FlutterRbConfig
4
+ def initialize(
5
+ flutter_checks,
6
+ android_checks,
7
+ ios_checks
8
+ )
9
+ @flutter_checks = flutter_checks
10
+ @android_checks = android_checks
11
+ @ios_checks = ios_checks
12
+ end
13
+
14
+ attr_accessor :flutter_checks, :android_checks, :ios_checks
15
+ end
16
+ end
@@ -0,0 +1,56 @@
1
+ require_relative './flutter_rb_config'
2
+ require_relative '../checks/plugin_directories_check'
3
+
4
+ require 'yaml'
5
+
6
+ module FlutterRb
7
+ # Class that initialize configuration
8
+ class FlutterRbConfigInitializer
9
+ FLUTTER_CHECKS = [
10
+ PluginDirectoriesCheck.new,
11
+ PluginPubspecNameCheck.new,
12
+ PluginPubspecDescriptionCheck.new,
13
+ PluginPubspecVersionCheck.new,
14
+ PluginPubspecAuthorCheck.new,
15
+ PluginPubspecHomepageCheck.new,
16
+ PluginPubspecEffectiveDartCheck.new
17
+ ].freeze
18
+
19
+ ANDROID_CHECKS = [
20
+ PluginGradleAndroidPackageCheck.new,
21
+ PluginGradleVersionCheck.new
22
+ ].freeze
23
+
24
+ IOS_CHECKS = [
25
+ PluginPodspecNameCheck.new,
26
+ PluginPodspecVersionCheck.new,
27
+ PluginPodspecAuthorsCheck.new,
28
+ PluginPodspecSourceCheck.new
29
+ ].freeze
30
+
31
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Layout/LineLength
32
+ def parse(path)
33
+ config = YAML.load_file(path)['include']
34
+ flutter_checks = []
35
+ flutter_checks += config['flutter'].map { |check| Object.const_get("FlutterRb::#{check}").new } unless config['flutter'].nil?
36
+ android_checks = []
37
+ android_checks += config['android'].map { |check| Object.const_get("FlutterRb::#{check}").new } unless config['android'].nil?
38
+ ios_checks = []
39
+ ios_checks += config['ios'].map { |check| Object.const_get("FlutterRb::#{check}").new } unless config['ios'].nil?
40
+ FlutterRbConfig.new(
41
+ flutter_checks.empty? ? FLUTTER_CHECKS : flutter_checks,
42
+ android_checks.empty? ? ANDROID_CHECKS : android_checks,
43
+ ios_checks.empty? ? IOS_CHECKS : ios_checks
44
+ )
45
+ end
46
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Layout/LineLength
47
+
48
+ def default
49
+ FlutterRbConfig.new(
50
+ FLUTTER_CHECKS,
51
+ ANDROID_CHECKS,
52
+ IOS_CHECKS
53
+ )
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,53 @@
1
+ require_relative './specs/flutter/pubspec'
2
+ require_relative './specs/flutter/dev_dependency'
3
+ require_relative './specs/flutter/platform_plugin'
4
+ require_relative './specs/android/android_folder'
5
+ require_relative './specs/android/gradle'
6
+ require_relative './specs/ios/ios_folder'
7
+
8
+ require 'yaml'
9
+
10
+ module FlutterRb
11
+ # Project representation
12
+ class Project
13
+ def initialize(
14
+ path,
15
+ pubspec,
16
+ android_folder,
17
+ ios_folder
18
+ )
19
+ @path = path
20
+ @pubspec = pubspec
21
+ @android_folder = android_folder
22
+ @ios_folder = ios_folder
23
+ end
24
+
25
+ attr_accessor :path, :pubspec, :android_folder, :ios_folder
26
+ end
27
+
28
+ # Flutter plugin project parser
29
+ class ProjectParser
30
+ def initialize(path)
31
+ @path = path
32
+ end
33
+
34
+ def project
35
+ File.exist?("#{@path}/pubspec.yaml") ? parse_project : nil
36
+ end
37
+
38
+ private
39
+
40
+ def parse_project
41
+ pubspec_path = "#{@path}/pubspec.yaml"
42
+ android_path = "#{@path}/android"
43
+ ios_path = "#{@path}/ios"
44
+ pubspec = PubspecParser.new(pubspec_path, YAML.load_file(pubspec_path)).parse
45
+ Project.new(
46
+ @path,
47
+ pubspec,
48
+ File.exist?(android_path) ? AndroidFolder.new(android_path) : nil,
49
+ File.exist?(ios_path) ? IOSFolder.new(ios_path, pubspec) : nil
50
+ )
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ require_relative './gradle'
2
+
3
+ module FlutterRb
4
+ # Android project representation
5
+ class AndroidFolder
6
+ def initialize(path)
7
+ @path = path
8
+ @gradle = GradleParser.new(@path).parse
9
+ end
10
+
11
+ attr_reader :path, :gradle
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'json'
2
+
3
+ module FlutterRb
4
+ # Gradle representation
5
+ class Gradle
6
+ def initialize(path, version)
7
+ @path = path
8
+ @version = version
9
+ end
10
+
11
+ attr_reader :path, :version
12
+ end
13
+
14
+ # Gradle parser
15
+ class GradleParser
16
+ def initialize(path)
17
+ @path = path
18
+ end
19
+
20
+ def parse
21
+ `gradle -p #{@path} -q prepareInfo`
22
+ info_file = File.read "#{@path}/flutter_rb_gradle_plugin_output.json"
23
+ info = JSON.parse info_file
24
+ Gradle.new(@path, info['version'])
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module FlutterRb
2
+ # Dev dependency, contains name and version
3
+ class DevDependency
4
+ def initialize(name, version)
5
+ @name = name
6
+ @version = version
7
+ end
8
+
9
+ attr_reader :name, :version
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module FlutterRb
2
+ # Flutter plugin, contains platform, package and plugin class
3
+ class PlatformPlugin
4
+ def initialize(platform, package, plugin_class)
5
+ @platform = platform
6
+ @package = package
7
+ @plugin_class = plugin_class
8
+ end
9
+
10
+ attr_reader :platform, :package, :plugin_class
11
+ end
12
+
13
+ # Supported platforms for this tool
14
+ class Platform
15
+ ANDROID = 'android'.freeze
16
+ IOS = 'ios'.freeze
17
+ end
18
+ end
@@ -0,0 +1,69 @@
1
+ require_relative './pubspec_info'
2
+ require_relative './dev_dependency'
3
+ require_relative './platform_plugin'
4
+
5
+ module FlutterRb
6
+ # pubspec.yaml representation
7
+ class Pubspec
8
+ def initialize(
9
+ path,
10
+ pubspec_info,
11
+ dev_dependencies,
12
+ platform_plugins
13
+ )
14
+ @path = path
15
+ @pubspec_info = pubspec_info
16
+ @dev_dependencies = dev_dependencies
17
+ @platform_plugins = platform_plugins
18
+ end
19
+
20
+ attr_reader :path, :pubspec_info, :dev_dependencies, :platform_plugins
21
+ end
22
+
23
+ # pubspec.yaml parser
24
+ class PubspecParser
25
+ def initialize(path, pubspec)
26
+ @path = path
27
+ @pubspec = pubspec
28
+ end
29
+
30
+ def parse
31
+ Pubspec.new(
32
+ @path,
33
+ pubspec_info(@pubspec),
34
+ dev_dependencies(@pubspec),
35
+ platform_plugins(@pubspec)
36
+ )
37
+ end
38
+
39
+ def pubspec_info(pubspec)
40
+ PubspecInfo.new(
41
+ pubspec['name'],
42
+ pubspec['description'],
43
+ pubspec['version'],
44
+ pubspec['author'],
45
+ pubspec['homepage']
46
+ )
47
+ end
48
+
49
+ def dev_dependencies(pubspec)
50
+ pubspec['dev_dependencies']&.map do |dev_dependency|
51
+ DevDependency.new(
52
+ dev_dependency.first,
53
+ dev_dependency.last
54
+ )
55
+ end
56
+ end
57
+
58
+ def platform_plugins(pubspec)
59
+ pubspec.dig('flutter', 'plugin', 'platforms')&.map do |platform_plugin|
60
+ plugin_info = platform_plugin.last
61
+ PlatformPlugin.new(
62
+ plugin_info['package'],
63
+ plugin_info['pluginClass'],
64
+ platform_plugin.first == Platform::ANDROID ? Platform::ANDROID : Platform::IOS
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ module FlutterRb
2
+ # Flutter plugin info from pubspec.yaml
3
+ class PubspecInfo
4
+ def initialize(
5
+ name,
6
+ description,
7
+ version,
8
+ author,
9
+ homepage
10
+ )
11
+ @name = name
12
+ @description = description
13
+ @version = version
14
+ @author = author
15
+ @homepage = homepage
16
+ end
17
+
18
+ attr_reader :name, :description, :version, :author, :homepage
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require_relative './podspec'
2
+
3
+ module FlutterRb
4
+ # iOS representation
5
+ class IOSFolder
6
+ def initialize(path, pubspec)
7
+ @path = path
8
+ podspec_path = "#{path}/#{pubspec.pubspec_info.name}.podspec"
9
+ @podspec = File.exist?(podspec_path) ? PodspecParser.new(podspec_path).parse : nil
10
+ end
11
+
12
+ attr_reader :path, :podspec
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ require 'cocoapods'
2
+
3
+ module FlutterRb
4
+ # Podspec representation
5
+ class Podspec
6
+ def initialize(
7
+ path,
8
+ name,
9
+ version,
10
+ authors,
11
+ source
12
+ )
13
+ @path = path
14
+ @name = name
15
+ @version = version
16
+ @authors = authors
17
+ @source = source
18
+ end
19
+
20
+ attr_reader :path, :name, :version, :authors, :source
21
+ end
22
+
23
+ # Podspec parser
24
+ class PodspecParser
25
+ def initialize(path)
26
+ @path = path
27
+ end
28
+
29
+ def parse
30
+ podspec = Pod::Specification.from_file(@path)
31
+ @podspec = Podspec.new(
32
+ @path,
33
+ podspec.name,
34
+ podspec.version.version,
35
+ podspec.authors.nil? ? podspec.author : podspec.authors,
36
+ podspec.source
37
+ )
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ require 'colorize'
2
+
3
+ module FlutterRb
4
+ # Check report
5
+ class CheckReport
6
+ def initialize(
7
+ check_name,
8
+ check_report_status,
9
+ message,
10
+ path
11
+ )
12
+ @check_name = check_name
13
+ @check_report_status = check_report_status
14
+ @message = message
15
+ @path = path
16
+ end
17
+
18
+ def print(colorize: true)
19
+ if colorize
20
+ status_color = color_for_report_status(@check_report_status)
21
+ " * [#{@check_report_status.colorize(status_color)}] #{@check_name}: #{@message}"
22
+ else
23
+ " * [#{@check_report_status}] #{@check_name}: #{@message}"
24
+ end
25
+ end
26
+
27
+ def color_for_report_status(check_report_status)
28
+ case check_report_status
29
+ when CheckReportStatus::NORMAL
30
+ :green
31
+ when CheckReportStatus::WARNING
32
+ :yellow
33
+ when CheckReportStatus::ERROR
34
+ :red
35
+ end
36
+ end
37
+
38
+ attr_reader :check_name, :check_report_status, :message, :path
39
+ end
40
+
41
+ # Check report status
42
+ class CheckReportStatus
43
+ NORMAL = 'normal'.freeze
44
+ WARNING = 'warning'.freeze
45
+ ERROR = 'error'.freeze
46
+ end
47
+ end
data/lib/flutter_rb.rb ADDED
@@ -0,0 +1,93 @@
1
+ require_relative './flutter_rb/project/project'
2
+ require_relative './flutter_rb/checks/plugin_directories_check'
3
+ require_relative './flutter_rb/checks/plugin_pubspec_check'
4
+ require_relative './flutter_rb/checks/plugin_gradle_check'
5
+ require_relative './flutter_rb/checks/plugin_podspec_check'
6
+ require_relative './flutter_rb/config/flutter_rb_config_initializer'
7
+
8
+ require_relative './checkstyle_report/checkstyle_report'
9
+
10
+ module FlutterRb
11
+ # Start FlutterRb checks
12
+ class FlutterRb
13
+ def start(path, with_report)
14
+ project = ProjectParser.new(path).project
15
+ if project.nil?
16
+ exit_with_no_project
17
+ else
18
+ check_project(
19
+ project,
20
+ path,
21
+ with_report
22
+ )
23
+ end
24
+ end
25
+
26
+ def exit_with_no_project
27
+ puts 'No project'
28
+ exit(-1)
29
+ end
30
+
31
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
32
+ def check_project(project, path, with_report)
33
+ config_initializer = FlutterRbConfigInitializer.new
34
+ config_path = "#{path}/.flutter_rb.yaml"
35
+ config = File.exist?(config_path) ? config_initializer.parse(config_path) : config_initializer.default
36
+ checks = explore_project(
37
+ project,
38
+ config.flutter_checks,
39
+ config.android_checks,
40
+ config.ios_checks
41
+ )
42
+ checks.each { |check| puts check.print }
43
+ errors = checks.reject { |check| check.check_report_status == CheckReportStatus::NORMAL }
44
+ create_report(path, checks) if with_report
45
+ exit(errors.empty? ? 0 : -1)
46
+ end
47
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
48
+
49
+ def explore_project(
50
+ project,
51
+ flutter_checks,
52
+ android_checks,
53
+ ios_checks
54
+ )
55
+ result = []
56
+ result += flutter_checks.map { |check| check.check(project) }
57
+ result += android_checks.map { |check| check.check(project) } unless project.android_folder.nil?
58
+ result += ios_checks.map { |check| check.check(project) } unless project.ios_folder.nil?
59
+ result
60
+ end
61
+
62
+ # rubocop:disable Metrics/MethodLength
63
+ def create_report(path, checks)
64
+ errors = checks.map do |check|
65
+ CheckstyleReport::CheckstyleError.new(
66
+ level_for_report(check.check_report_status),
67
+ check.message,
68
+ check.path,
69
+ 0,
70
+ 0,
71
+ check.check_name
72
+ )
73
+ end
74
+ CheckstyleReport::CheckstyleReport.new(
75
+ path,
76
+ 'frb-checkstyle-report',
77
+ errors
78
+ ).create_report
79
+ end
80
+ # rubocop:enable Metrics/MethodLength
81
+
82
+ def level_for_report(check_report_status)
83
+ case check_report_status
84
+ when CheckReportStatus::NORMAL
85
+ CheckstyleReport::CheckstyleError::SAVERITY_NORMAL
86
+ when CheckReportStatus::WARNING
87
+ CheckstyleReport::CheckstyleError::SAVERITY_WARNING
88
+ when CheckReportStatus::ERROR
89
+ CheckstyleReport::CheckstyleError::SAVERITY_ERROR
90
+ end
91
+ end
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flutter_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - Artem Fomchenkov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cocoapods
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.10.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.10.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.8.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.13.6
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.13.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 5.14.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 5.14.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 12.3.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 12.3.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: '1.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: '1.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.21.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.21.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov-lcov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 0.8.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 0.8.0
125
+ description:
126
+ email: artem.fomchenkov@outlook.com
127
+ executables:
128
+ - frb
129
+ extensions: []
130
+ extra_rdoc_files:
131
+ - README.md
132
+ files:
133
+ - LICENSE
134
+ - README.md
135
+ - bin/frb
136
+ - lib/checkstyle_report/checkstyle_report.rb
137
+ - lib/flutter_rb.rb
138
+ - lib/flutter_rb/checks/check.rb
139
+ - lib/flutter_rb/checks/plugin_directories_check.rb
140
+ - lib/flutter_rb/checks/plugin_gradle_check.rb
141
+ - lib/flutter_rb/checks/plugin_podspec_check.rb
142
+ - lib/flutter_rb/checks/plugin_pubspec_check.rb
143
+ - lib/flutter_rb/config/flutter_rb_config.rb
144
+ - lib/flutter_rb/config/flutter_rb_config_initializer.rb
145
+ - lib/flutter_rb/project/project.rb
146
+ - lib/flutter_rb/project/specs/android/android_folder.rb
147
+ - lib/flutter_rb/project/specs/android/gradle.rb
148
+ - lib/flutter_rb/project/specs/flutter/dev_dependency.rb
149
+ - lib/flutter_rb/project/specs/flutter/platform_plugin.rb
150
+ - lib/flutter_rb/project/specs/flutter/pubspec.rb
151
+ - lib/flutter_rb/project/specs/flutter/pubspec_info.rb
152
+ - lib/flutter_rb/project/specs/ios/ios_folder.rb
153
+ - lib/flutter_rb/project/specs/ios/podspec.rb
154
+ - lib/flutter_rb/report/check_report.rb
155
+ homepage: http://github.com/fartem/flutter-rb
156
+ licenses:
157
+ - MIT
158
+ metadata: {}
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: 2.7.0
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubygems_version: 3.1.6
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: A Ruby tool for checking a Flutter plugin structure
179
+ test_files: []