fastlane-plugin-fastci 0.0.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.
@@ -0,0 +1,262 @@
1
+ require 'gym'
2
+ require 'fastlane_core'
3
+ require 'fastlane/action'
4
+ include Fastlane::Helper
5
+
6
+ module Fastlane
7
+ module Actions
8
+ # 打包
9
+ class PackageAction < Action
10
+ def self.run(params)
11
+
12
+ # 入参配置
13
+ configuration = params[:configuration] || "Debug"
14
+ export_method = params[:export_method] || "development"
15
+ build = params[:build] || nil
16
+ is_analyze_swiftlint = params[:is_analyze_swiftlint] || false
17
+ is_detect_duplicity_code = params[:is_detect_duplicity_code] || false
18
+ is_detect_unused_code = params[:is_detect_unused_code] || false
19
+ is_detect_unused_image = params[:is_detect_unused_image] || false
20
+ if export_method == "app-store"
21
+ configuration = "Release"
22
+ end
23
+
24
+ # 清理上一次的打包缓存
25
+ FileUtils.rm_rf(Dir.glob("#{Constants.BUILD_LOG_DIR}/*"))
26
+ FileUtils.rm_rf(Dir.glob("#{Constants.IPA_OUTPUT_DIR}/*"))
27
+
28
+ # 安装证书
29
+ InstallCertificateAction.run({})
30
+ # 安装 provisioningProfile
31
+ InstallProfileAction.run({})
32
+
33
+ scheme = Environment.scheme
34
+ # 更改项目build号
35
+ UpdateBuildNumberAction.run(
36
+ build: build
37
+ )
38
+ time = Time.new.strftime("%Y%m%d%H%M")
39
+ version = Actions::GetVersionNumberAction.run(target: "#{Environment.target}")
40
+ build = Actions::GetBuildNumberAction.run({})
41
+ # 生成ipa包的名字格式
42
+ ipaName = "#{Environment.scheme}_#{export_method}_#{version}_#{build}.ipa"
43
+
44
+ # 获取 Extension 的 Bundle ID(可能有多个,用逗号分隔)
45
+ extension_bundle_ids = Environment.extension_bundle_ids
46
+ extension_profile_names = []
47
+ # profile 名字
48
+ profile_name = ""
49
+
50
+ case export_method
51
+ when "development"
52
+ profile_name = Environment.provisioningProfiles_development
53
+ extension_profile_names = Environment.extension_profiles_development
54
+ when "ad-hoc"
55
+ profile_name = Environment.provisioningProfiles_adhoc
56
+ extension_profile_names = Environment.extension_profiles_adhoc
57
+ when "app-store"
58
+ profile_name = Environment.provisioningProfiles_appstore
59
+ extension_profile_names = Environment.extension_profiles_appstore
60
+ else
61
+ raise "Unsupported export method: #{export_method}"
62
+ end
63
+
64
+ # 组装 provisioningProfiles
65
+ provisioningProfiles_map = {
66
+ "#{Environment.bundleID}" => "#{profile_name}"
67
+ }
68
+ extension_bundle_ids.each_with_index do |ext_bundle_id, idx|
69
+ provisioningProfiles_map[ext_bundle_id.strip] = extension_profile_names[idx]&.strip
70
+ end
71
+
72
+ UI.message("*************| 开始打包 |*************")
73
+
74
+ options = {
75
+ clean: true,
76
+ silent: true,
77
+ workspace: Environment.workspace,
78
+ scheme: scheme,
79
+ configuration: configuration,
80
+ buildlog_path: Constants.BUILD_LOG_DIR,
81
+ output_name: ipaName,
82
+ output_directory: Constants.IPA_OUTPUT_DIR,
83
+ export_options: {
84
+ method: export_method,
85
+ provisioningProfiles: provisioningProfiles_map
86
+ }
87
+ }
88
+ config = FastlaneCore::Configuration.create(Gym::Options.available_options, options)
89
+ Gym::Manager.new.work(config)
90
+
91
+ UI.message("*************| 打包完成 |*************")
92
+
93
+ UI.message("*************| 复制打包产物 |*************")
94
+ # 定义桌面路径
95
+ desktop_path = File.expand_path("~/Desktop")
96
+ output_path = File.join(desktop_path, "BuildOutput_#{scheme}")
97
+ target_path = File.join(output_path, "#{build}")
98
+ FileUtils.mkdir_p(target_path)
99
+ # 构建复制到桌面
100
+ Dir.glob("#{Constants.IPA_OUTPUT_DIR}/*").each do |file|
101
+ UI.message("准备复制文件:#{file} 到 #{target_path}")
102
+ FileUtils.cp_r(file, target_path)
103
+ end
104
+
105
+ # UI.message("*************| 重置 Git 仓库 |*************")
106
+ # 重置 Git 仓库
107
+ # system("git reset --hard")
108
+
109
+ ipa_path = "#{Constants.IPA_OUTPUT_DIR}/#{ipaName}"
110
+
111
+ if export_method == "app-store"
112
+ notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-打包完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
113
+ NotiDingdingAction.run(notiText: notiText)
114
+
115
+ if CommonHelper.is_validate_string(Environment.connect_key_id) && CommonHelper.is_validate_string(Environment.connect_issuer_id)
116
+
117
+ UploadStoreAction.run({})
118
+ notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-上传完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
119
+ NotiDingdingAction.run(notiText: notiText)
120
+ end
121
+ else
122
+ # 上传蒲公英
123
+ pgy_upload_info = UploadPgyAction.run(
124
+ "ipa_path": ipa_path
125
+ )
126
+ qrCode = pgy_upload_info["buildQRCodeURL"]
127
+
128
+ # 钉钉通知
129
+ notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-打包完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
130
+ if CommonHelper.is_validate_string(qrCode)
131
+ notiText << "\n\n⬇️⬇️⬇️ 扫码安装 ⬇️⬇️⬇️\n\n![screenshot](#{qrCode})"
132
+ end
133
+ NotiDingdingAction.run(notiText: notiText)
134
+ end
135
+
136
+ # 代码分析
137
+ if is_analyze_swiftlint && export_method != "app-store"
138
+ analyze_swiftlint(is_from_package: true, configuration: configuration)
139
+ # 结果复制到桌面
140
+ FileUtils.cp(SWIFTLINT_HTML_FILE, target_path)
141
+ FileUtils.cp(SWIFTLINT_ANALYZE_HTML_FILE, target_path)
142
+ UI.message("*************| 代码分析完成 |*************")
143
+ else
144
+ UI.message("*************| 跳过代码分析 |*************")
145
+ end
146
+
147
+ # 重复代码检查
148
+ if is_detect_duplicity_code && export_method != "app-store"
149
+ detect_code_duplicity(is_all: true)
150
+ # 结果复制到桌面
151
+ FileUtils.cp(DUPLICITY_CODE_HTML_FILE, target_path)
152
+ UI.message("*************| 重复代码检查完成 |*************")
153
+ else
154
+ UI.message("*************| 跳过重复代码检查 |*************")
155
+ end
156
+
157
+ # 无用代码检查
158
+ if is_detect_unused_code && export_method != "app-store"
159
+ DetectUnusedCodeAction.run(
160
+ is_from_package: true,
161
+ configuration: configuration
162
+ )
163
+ # 结果复制到桌面
164
+ FileUtils.cp(Constants.UNUSED_CODE_HTML_FILE, target_path)
165
+ UI.message("*************| 无用代码检查完成 |*************")
166
+ else
167
+ UI.message("*************| 跳过无用代码检查 |*************")
168
+ end
169
+
170
+ # 无用图片检查
171
+ if is_detect_unused_image && export_method != "app-store"
172
+ DetectUnusedImageAction.run({})
173
+ # 结果复制到桌面
174
+ FileUtils.cp(Constants.UNUSED_IMAGE_HTML_FILE, target_path)
175
+ UI.message("*************| 无用图片检查完成 |*************")
176
+ else
177
+ UI.message("*************| 跳过未使用图片检查 |*************")
178
+ end
179
+
180
+ if is_swiftlint ||
181
+ is_detect_duplicity_code ||
182
+ is_detect_unused_code ||
183
+ is_detect_unused_image
184
+ # 钉钉通知
185
+ notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-代码检查完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
186
+ NotiDingdingAction.run(notiText: notiText)
187
+ else
188
+ UI.message("*************| 跳过代码检查 |*************")
189
+ end
190
+
191
+ UI.message("*************| 脚本完成 |*************")
192
+ end
193
+
194
+ def self.description
195
+ "打包"
196
+ end
197
+
198
+ def self.available_options
199
+ [
200
+ FastlaneCore::ConfigItem.new(
201
+ key: :configuration,
202
+ description: "编译环境 Release or Debug",
203
+ optional: true,
204
+ default_value: "Release",
205
+ type: String
206
+ ),
207
+ FastlaneCore::ConfigItem.new(
208
+ key: :export_method,
209
+ description: "打包方式 ad-hoc, enterprise, app-store, development",
210
+ optional: true,
211
+ default_value: "development",
212
+ type: String
213
+ ),
214
+ FastlaneCore::ConfigItem.new(
215
+ key: :build,
216
+ description: "不采取自动更新,自定义 build 号",
217
+ optional: true,
218
+ default_value: nil,
219
+ type: String
220
+ ),
221
+ FastlaneCore::ConfigItem.new(
222
+ key: :is_analyze_code,
223
+ description: "是否代码分析",
224
+ optional: true,
225
+ default_value: false,
226
+ type: Boolean
227
+ ),
228
+ FastlaneCore::ConfigItem.new(
229
+ key: :is_detect_code_duplicity,
230
+ description: "是否检查重复代码",
231
+ optional: true,
232
+ default_value: false,
233
+ type: Boolean
234
+ ),
235
+ FastlaneCore::ConfigItem.new(
236
+ key: :is_detect_unused_code,
237
+ description: "是否检查无用代码",
238
+ optional: true,
239
+ default_value: false,
240
+ type: Boolean
241
+ ),
242
+ FastlaneCore::ConfigItem.new(
243
+ key: :is_detect_unused_image,
244
+ description: "是否检查无用图片",
245
+ optional: true,
246
+ default_value: false,
247
+ type: Boolean
248
+ ),
249
+ ]
250
+ end
251
+
252
+ def self.is_supported?(platform)
253
+ platform == :ios
254
+ end
255
+
256
+ def self.category
257
+ :building
258
+ end
259
+
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,65 @@
1
+ require 'fastlane/action'
2
+ include Fastlane::Helper
3
+
4
+ module Fastlane
5
+ module Actions
6
+ # 更新 build 号
7
+ class UpdateBuildNumberAction < Action
8
+ def self.run(params)
9
+
10
+ build = params[:build] || nil
11
+ unless CommonHelper.is_validate_string(build)
12
+ currentTime = Time.new.strftime("%Y%m%d")
13
+ build = CommonHelper.get_cached_build_number
14
+
15
+ if build.include?("#{currentTime}.")
16
+ # 当天版本 计算迭代版本号
17
+ lastStr = build.split('.').last
18
+ lastNum = lastStr.to_i
19
+ lastNum += 1
20
+ lastStr = lastNum.to_s.rjust(2, '0')
21
+ build = "#{currentTime}.#{lastStr}"
22
+ else
23
+ # 非当天版本 build 重置
24
+ build = "#{currentTime}.01"
25
+ end
26
+
27
+ # 缓存新的 build 号
28
+ CommonHelper.write_cached_txt(Constants.BUILD_NUMBER_FILE, build)
29
+ end
30
+
31
+ UI.message("*************| 更新 build #{build} |*************")
32
+ # 更改项目 build 号
33
+ Actions::IncrementBuildNumberAction.run(
34
+ build_number: build
35
+ )
36
+
37
+ end
38
+
39
+ def self.description
40
+ "更新 build 号"
41
+ end
42
+
43
+ def self.available_options
44
+ [
45
+ FastlaneCore::ConfigItem.new(
46
+ key: :build,
47
+ description: "不采取自动更新,自定义 build 号",
48
+ optional: true,
49
+ default_value: nil,
50
+ type: String
51
+ ),
52
+ ]
53
+ end
54
+
55
+ def self.is_supported?(platform)
56
+ platform == :ios
57
+ end
58
+
59
+ def self.category
60
+ :building
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,47 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/plugin/pgyer'
3
+ include Fastlane::Helper
4
+
5
+ module Fastlane
6
+ module Actions
7
+ # 上传蒲公英
8
+ class UploadPgyAction < Action
9
+ def self.run(params)
10
+ UI.message("*************| 开始上传蒲公英 |*************")
11
+
12
+ unless CommonHelper.is_validate_string(Environment.pgy_api_key)
13
+ UI.message("*************| 没有配置 pgy_api_key |*************")
14
+ return
15
+ end
16
+
17
+ ipa_path = params[:ipa_path] || ""
18
+
19
+ pgyinfo = PgyerAction.run(
20
+ ipa: ipa_path,
21
+ api_key: Environment.pgy_api_key,
22
+ password: Environment.pgy_password,
23
+ install_type: "2"
24
+ )
25
+
26
+ return pgyinfo
27
+ end
28
+
29
+ def self.description
30
+ "上传蒲公英"
31
+ end
32
+
33
+ def self.available_options
34
+ []
35
+ end
36
+
37
+ def self.is_supported?(platform)
38
+ platform == :ios
39
+ end
40
+
41
+ def self.category
42
+ :building
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,50 @@
1
+ require 'fastlane/action'
2
+ include Fastlane::Helper
3
+
4
+ module Fastlane
5
+ module Actions
6
+ # 上传 AppStore
7
+ class UploadStoreAction < Action
8
+ def self.run(params)
9
+ UI.message("*************| 开始上传 AppStore |*************")
10
+
11
+ other_action.app_store_connect_api_key(
12
+ key_id: Environment.connect_key_id,
13
+ issuer_id: Environment.connect_issuer_id,
14
+ key_filepath: File.expand_path("./AuthKey_#{Environment.connect_key_id}.p8"),
15
+ duration: 1200, # optional (maximum 1200)
16
+ in_house: false # optional but may be required if using match/sigh
17
+ )
18
+ other_action.upload_to_app_store(
19
+ skip_metadata: false,
20
+ skip_screenshots: true,
21
+ force: true,
22
+ submit_for_review: false,
23
+ automatic_release: false,
24
+ release_notes: params[:release_notes]
25
+ )
26
+
27
+ end
28
+
29
+ def self.description
30
+ "上传 AppStore"
31
+ end
32
+
33
+ def self.available_options
34
+ [
35
+ FastlaneCore::ConfigItem.new(
36
+ key: :release_notes,
37
+ description: "更新文案, 格式为 { "zh-Hans" => "修复问题", "en-US" => "bugfix"} ",
38
+ optional: false,
39
+ type: Hash
40
+ )
41
+ ]
42
+ end
43
+
44
+ def self.is_supported?(platform)
45
+ platform == :ios
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,108 @@
1
+ require 'fastlane_core/ui/ui'
2
+ require 'fileutils'
3
+
4
+ module Fastlane
5
+ module Helper
6
+ class CommonHelper
7
+
8
+ def self.read_cached_txt(file_name)
9
+ if File.exist?(file_name)
10
+ File.read(file_name).strip
11
+ else
12
+ nil
13
+ end
14
+ end
15
+
16
+ def self.write_cached_txt(file_name, content)
17
+ dir_name = File.dirname(file_name)
18
+ FileUtils.mkdir_p(dir_name) unless Dir.exist?(dir_name)
19
+
20
+ File.open(file_name, "w") { |file| file.write(content) }
21
+ end
22
+
23
+ def self.get_cached_build_number
24
+ cached_build = read_cached_txt(Constants.BUILD_NUMBER_FILE)
25
+ currentTime = Time.new.strftime("%Y%m%d")
26
+
27
+ if cached_build.nil? || cached_build.empty?
28
+ # 初始化 build
29
+ return "#{currentTime}.00"
30
+ else
31
+ return cached_build
32
+ end
33
+ end
34
+
35
+ # 判断字段是否有值
36
+ def self.is_validate_string(variable)
37
+ if variable.nil? || variable.empty?
38
+ return false
39
+ end
40
+ return true
41
+ end
42
+
43
+ # 获取当前 commit_hash 到最新 commit 下所有变更的 swift 文件
44
+ def self.get_git_modified_swift_files(commit_hash)
45
+ modified_files = sh("git diff --name-only --diff-filter=d #{commit_hash}..origin/develop").split("\n")
46
+ swift_files = modified_files.select { |file| file.end_with?('.swift') }
47
+ return swift_files
48
+ end
49
+
50
+ # 缓存最新 git
51
+ def self.cache_git_commit
52
+ latest_commit = sh("git rev-parse HEAD").strip
53
+ write_cached_txt(COMMIT_HASH_FILE, latest_commit)
54
+ end
55
+
56
+ # 从构建日志中提取 index store 路径的辅助方法
57
+ def self.extract_index_store_path(log_file)
58
+ begin
59
+ log_content = File.read(log_file)
60
+
61
+ # 在日志中查找 DerivedData 路径
62
+ derived_data_match = log_content.match(/DerivedData\/([^\/]+)-([^\/]+)/)
63
+ if derived_data_match
64
+ project_name = derived_data_match[1]
65
+ hash_suffix = derived_data_match[2]
66
+
67
+ # 构建可能的 index store 路径
68
+ derived_data_base = File.expand_path("~/Library/Developer/Xcode/DerivedData")
69
+ project_dir = "#{derived_data_base}/#{project_name}-#{hash_suffix}"
70
+
71
+ # Xcode 14+ 使用 Index.noindex
72
+ index_paths = [
73
+ "#{project_dir}/Index.noindex/DataStore",
74
+ "#{project_dir}/Index/DataStore"
75
+ ]
76
+
77
+ # 返回第一个存在的路径
78
+ index_paths.each do |path|
79
+ if File.exist?(path)
80
+ puts "*************| 找到 index store: #{path} |*************"
81
+ return path
82
+ end
83
+ end
84
+ end
85
+
86
+ puts "*************| 在构建日志中未找到有效的 index store 路径 |*************"
87
+ return nil
88
+ rescue => e
89
+ puts "*************| 解析构建日志失败: #{e.message} |*************"
90
+ return nil
91
+ end
92
+ end
93
+
94
+ # 生成并打开 html
95
+ def self.generate_and_open_html(title, python_file, origin_file, html_file)
96
+ python_path = File.expand_path("../../python/#{python_file}", __dir__)
97
+ origin_file_path = File.expand_path(origin_file)
98
+ html_file_path = File.expand_path(html_file)
99
+
100
+ system("python3 \"#{python_path}\" \"#{title}\" \"#{origin_file_path}\" \"#{html_file_path}\"")
101
+ system("open \"#{html_file_path}\"")
102
+
103
+ File.delete(origin_file_path)
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ module Fastlane
2
+ module Helper
3
+ module Constants
4
+ # cache 文件
5
+ def self.BUILD_NUMBER_FILE
6
+ "fastlane_cache/build_cache.txt"
7
+ end
8
+ def self.COMMIT_HASH_FILE
9
+ "fastlane_cache/commit_cache.txt"
10
+ end
11
+ def self.SWIFTLINT_ANALYZE_FILE
12
+ "fastlane_cache/temp/swiftlint_analyze_result.txt"
13
+ end
14
+ def self.SWIFTLINT_ANALYZE_HTML_FILE
15
+ "fastlane_cache/html/analyze_lint_report.html"
16
+ end
17
+ def self.DUPLICITY_CODE_MODIFIED_FILE
18
+ "fastlane_cache/temp/duplicity_code_modified_files.txt"
19
+ end
20
+ def self.DUPLICITY_CODE_FILE
21
+ "fastlane_cache/temp/duplicity_code_result.xml"
22
+ end
23
+ def self.DUPLICITY_CODE_HTML_FILE
24
+ "fastlane_cache/html/duplicity_code_report.html"
25
+ end
26
+ def self.UNUSED_CODE_FILE
27
+ "fastlane_cache/temp/unused_code_result.txt"
28
+ end
29
+ def self.UNUSED_CODE_HTML_FILE
30
+ "fastlane_cache/html/unused_code_report.html"
31
+ end
32
+ def self.UNUSED_IMAGE_FILE
33
+ "fastlane_cache/temp/unused_image_result.txt"
34
+ end
35
+ def self.UNUSED_IMAGE_HTML_FILE
36
+ "fastlane_cache/html/unused_image_report.html"
37
+ end
38
+
39
+ # bulid 产物
40
+ def self.BUILD_LOG_DIR
41
+ "fastlane_cache/build_logs"
42
+ end
43
+ def self.IPA_OUTPUT_DIR
44
+ "fastlane_cache/build_products"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,86 @@
1
+ module Fastlane
2
+ module Helper
3
+ module Environment
4
+ # 苹果密钥配置
5
+ def self.connect_key_id
6
+ ENV['CONNECT_KEY_ID']
7
+ end
8
+ def self.connect_issuer_id
9
+ ENV['CONNECT_ISSUER_ID']
10
+ end
11
+
12
+ # 项目配置
13
+ def self.scheme
14
+ ENV['SCHEME_NAME']
15
+ end
16
+ def self.target
17
+ ENV['TARGET_NAME']
18
+ end
19
+ def self.workspace
20
+ ENV['WORKSPACE']
21
+ end
22
+ def self.bundleID
23
+ ENV['BUNDLE_ID']
24
+ end
25
+ def self.extension_bundle_ids
26
+ ENV['EXTENSION_BUNDLE_IDS']&.split(",") || []
27
+ end
28
+ def self.schemes
29
+ ENV['SCHEMES_NAME']&.split(",") || []
30
+ end
31
+
32
+ # 描述文件配置
33
+ def self.provisioningProfile_folder_name
34
+ ENV['PROFILE_FOLDER_NAME']
35
+ end
36
+ def self.provisioningProfiles_development
37
+ ENV['PROFILE_DEVELOPMENT']
38
+ end
39
+ def self.provisioningProfiles_adhoc
40
+ ENV['PROFILE_ADHOC']
41
+ end
42
+ def self.provisioningProfiles_appstore
43
+ ENV['PROFILE_APPSTORE']
44
+ end
45
+ def self.extension_profiles_development
46
+ ENV['EXTENSION_PROFILES_DEVELOPMENT']&.split(",") || []
47
+ end
48
+ def self.extension_profiles_adhoc
49
+ ENV['EXTENSION_PROFILES_ADHOC']&.split(",") || []
50
+ end
51
+ def self.extension_profiles_appstore
52
+ ENV['EXTENSION_PROFILES_APPSTORE']&.split(",") || []
53
+ end
54
+
55
+ # p12 证书配置
56
+ def self.certificate_folder_name
57
+ ENV['PROFILE_FOLDER_NAME']
58
+ end
59
+ def self.certificate_development
60
+ ENV['CERTIFICATE_DEVELOPMENT']
61
+ end
62
+ def self.certificate_distribution
63
+ ENV['CERTIFICATE_DISTRIBUTION']
64
+ end
65
+ def self.certificate_password
66
+ ENV['CERTIFICATE_PASSWORD']
67
+ end
68
+ def self.keychain_password
69
+ ENV['KEYCHAIN_PASSWORD']
70
+ end
71
+
72
+ # 蒲公英配置
73
+ def self.pgy_api_key
74
+ ENV['PGY_API_KEY']
75
+ end
76
+ def self.pgy_password
77
+ ENV['PGY_PASSWORD']
78
+ end
79
+
80
+ # 钉钉配置
81
+ def self.dingdingToken
82
+ ENV['DINGDING_TOKEN']
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Fastci
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/fastci/version'
2
+
3
+ module Fastlane
4
+ module Fastci
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::Fastci.all_classes.each do |current|
15
+ require current
16
+ end