fastlane-plugin-fastci 0.0.19 → 0.0.30
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 +4 -4
- data/README.md +86 -1
- data/lib/fastlane/plugin/fastci/actions/check_zealot_version_action.rb +52 -0
- data/lib/fastlane/plugin/fastci/actions/package_action.rb +114 -91
- data/lib/fastlane/plugin/fastci/actions/sync_zealot_devices_action.rb +65 -0
- data/lib/fastlane/plugin/fastci/actions/upload_zealot_action.rb +58 -0
- data/lib/fastlane/plugin/fastci/actions/upload_zealot_dsym_action.rb +63 -0
- data/lib/fastlane/plugin/fastci/helper/environment.rb +12 -1
- data/lib/fastlane/plugin/fastci/helper/fastci_zealot_helper.rb +51 -0
- data/lib/fastlane/plugin/fastci/version.rb +1 -1
- metadata +23 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9eadcd995669c5cfd0d4d8a28b68667d0d18cdd710864eed98ed142e285c9b93
|
|
4
|
+
data.tar.gz: 2fa4908e62aedb5faa2ad21a5f6d4d5e210bf609848721c621856c84f80e9741
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1606d02bc136b88b61652ad9218f7a3428ba36a516eb578d738328b12750abeb04b9caa7f30eebe790efae4e4019961c6429089f8d0d247cdc8ebd76e5ad2252
|
|
7
|
+
data.tar.gz: 3cf569702228448922d1d20e296900fc2c7594d3c51d3f82ef6ea0e88addc85227f27c3ea050a81ad45ce0630e5a5647aeab82a800b3433e8430eb31fc555d7a
|
data/README.md
CHANGED
|
@@ -53,6 +53,7 @@ fastlane_cache/ # 插件缓存文件夹
|
|
|
53
53
|
功能:自动编译并导出 ipa 包,支持多种打包方式和集成多项检查。
|
|
54
54
|
生成完的 ipa 会放在桌面上,非 ` app-store ` 配置了蒲公英或 fir 参数会自动上传蒲公英或 fir。` app-store ` 和 ` testFlight ` 配置了商店参数会自动上传商店。
|
|
55
55
|
配置了 Sentry 参数会自动上传符号表。
|
|
56
|
+
配置了 Zealot 参数的非商店包也可自动上传,详见下方 Zealot 配置。
|
|
56
57
|
|
|
57
58
|
` build `: 不指定的话内部有递增逻辑,格式为 ` 20250905.15(日期+当天包的次数) `
|
|
58
59
|
|
|
@@ -71,7 +72,8 @@ package(
|
|
|
71
72
|
is_detect_unused_code: false, # 是否检测未使用代码
|
|
72
73
|
is_detect_unused_image: false, # 是否检测未使用图片
|
|
73
74
|
changelog: options[:changelog], # fir 更新日志
|
|
74
|
-
release_notes: options[:release_notes] # 配合 jenkins 传参上传 appstore 格式为 { \"zh-Hans\": \"修复问题\", \"en-US\": \"bugfix\"} JSON 字符串
|
|
75
|
+
release_notes: options[:release_notes], # 配合 jenkins 传参上传 appstore 格式为 { \"zh-Hans\": \"修复问题\", \"en-US\": \"bugfix\"} JSON 字符串
|
|
76
|
+
is_notice_dingding: options[:is_notice_dingding] # 配置钉钉token了,通过该参数控制是否发送通知
|
|
75
77
|
)
|
|
76
78
|
```
|
|
77
79
|
|
|
@@ -123,6 +125,89 @@ detect_unused_image(
|
|
|
123
125
|
|
|
124
126
|
---
|
|
125
127
|
|
|
128
|
+
### 6. Zealot(仅 iOS)
|
|
129
|
+
|
|
130
|
+
通过官方 [fastlane-plugin-zealot](https://github.com/tryzealot/fastlane-plugin-zealot) 封装以下独立 Action:
|
|
131
|
+
|
|
132
|
+
| Action | 用途 |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `upload_zealot` | 上传 IPA,返回版本与下载地址 |
|
|
135
|
+
| `upload_zealot_dsym` | 上传 iOS dSYM,支持 zip 或 xcarchive |
|
|
136
|
+
| `check_zealot_version` | 按 Bundle ID、版本号或 commit 查询版本 |
|
|
137
|
+
| `sync_zealot_devices` | 将 Apple 开发者账号中的 iOS 设备同步到 Zealot |
|
|
138
|
+
|
|
139
|
+
在本机环境文件或 CI 密钥中配置,真实 token 不要提交到仓库:
|
|
140
|
+
|
|
141
|
+
```dotenv
|
|
142
|
+
ZEALOT_ENDPOINT=https://zealot.example.com
|
|
143
|
+
ZEALOT_TOKEN=your-user-token
|
|
144
|
+
ZEALOT_CHANNEL_KEY=your-ios-channel-key
|
|
145
|
+
ZEALOT_UPLOAD_DSYM=false
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`package` 与 Fir 一样按 token 判断是否上传:配置 `ZEALOT_TOKEN` 后,自动上传 `development`、`ad-hoc`、`enterprise` 包;token 留空时跳过。上传时必须同时提供 `ZEALOT_ENDPOINT` 和 `ZEALOT_CHANNEL_KEY`。`app-store` 和 `testFlight` 保持原上传流程。
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
package(
|
|
152
|
+
export_method: "development",
|
|
153
|
+
is_upload_zealot_dsym: true, # 默认 false;仅 IPA 上传成功后执行
|
|
154
|
+
changelog: "iOS 更新说明"
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
也可以单独调用,不需要重新构建:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
result = upload_zealot(file: "./App.ipa", changelog: "iOS 更新说明")
|
|
162
|
+
# result:app_id、release_id、release_url、install_url、qrcode_url
|
|
163
|
+
|
|
164
|
+
upload_zealot_dsym(zip_file: "./App.app.dSYM.zip")
|
|
165
|
+
# 或指定 path: "./App.xcarchive";均未指定时使用本次 gym 产物。
|
|
166
|
+
|
|
167
|
+
exists = check_zealot_version(
|
|
168
|
+
bundle_id: "com.example.app",
|
|
169
|
+
release_version: "1.0",
|
|
170
|
+
build_version: "1"
|
|
171
|
+
)
|
|
172
|
+
# 也可用 git_commit 替代 release_version / build_version。
|
|
173
|
+
|
|
174
|
+
sync_zealot_devices(api_key_path: "./app_store_connect_api_key.json")
|
|
175
|
+
# 也可使用 username / team_id;设备同步不会在 package 中自动执行。
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
请求失败默认终止 lane,可传 `fail_on_error: false` 或设置 `ZEALOT_FAIL_ON_ERROR=false` 继续执行。版本查询返回 `true`(存在)、`false`(不存在)、`nil`(请求失败且允许继续);设备同步返回 `total`、`succeeded`、`failed`。token 在请求摘要中始终隐藏。
|
|
179
|
+
|
|
180
|
+
上传参数支持官方的 `password`、`timeout`、`verify_ssl`、`branch`、`git_commit` 等选项,使用 `bundle exec fastlane action upload_zealot` 查看。示例 Fastfile 也提供 `uploadZealot`、`uploadZealotDsym`、`checkZealotVersion`、`syncZealotDevices` 四个 lane。
|
|
181
|
+
|
|
182
|
+
依赖兼容:Zealot 的 `debug_file` 依赖 `ruby-macho < 3`,不能与 CocoaPods 1.17(依赖 4.x)放在同一 bundle。此类工程应将 CocoaPods 放入独立 Gemfile;使用 Faraday 1 的 Fastlane 工程还应将 `faraday-net_http` 限制为 `~> 1.0`。
|
|
183
|
+
|
|
184
|
+
## 发布到 RubyGems
|
|
185
|
+
|
|
186
|
+
工作流位于 [`.github/workflows/release.yml`](.github/workflows/release.yml)。使用 `1.0.0` 这样的纯版本标签,无需 `v` 前缀。推送数字开头的标签后,自动校验标签与 `lib/fastlane/plugin/fastci/version.rb` 中的 `VERSION` 完全一致,检查 Ruby 语法、构建 gem 并发布到 RubyGems。
|
|
187
|
+
|
|
188
|
+
首次使用需完成一次 [RubyGems Trusted Publishing 配置](https://guides.rubygems.org/trusted-publishing/):
|
|
189
|
+
|
|
190
|
+
用 gem 所有者账号打开 [fastlane-plugin-fastci](https://rubygems.org/gems/fastlane-plugin-fastci),进入 **Trusted publishers → Create**,填写:
|
|
191
|
+
|
|
192
|
+
| 字段 | 值 |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| Repository owner | `watermelon520` |
|
|
195
|
+
| Repository name | `fastlane-plugin-fastci` |
|
|
196
|
+
| Workflow filename | `release.yml` |
|
|
197
|
+
| Environment | 留空(可选) |
|
|
198
|
+
|
|
199
|
+
工作流使用官方 OIDC 短期凭据,不需要配置 `RUBYGEMS_API_KEY` 或创建 GitHub Environment。工作流文件在当前仓库内,Workflow Repository 两项留空。若以后设置 Environment,RubyGems 配置与工作流的 `environment` 必须保持一致。
|
|
200
|
+
|
|
201
|
+
每次发布先修改 `VERSION`,执行 `bundle install` 同步 `Gemfile.lock`,并提交本次拟发布的代码和工作流。然后推送对应标签,例如版本更新为 `0.0.30` 后:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
git push origin main
|
|
205
|
+
git tag -a 0.0.30 -m "Release 0.0.30"
|
|
206
|
+
git push origin 0.0.30
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
到 GitHub **Actions → Release to RubyGems** 查看结果。已发布版本不能覆盖;失败重跑前先确认该版本是否已经发布。只有打入标签提交的文件会被发布,本地未提交改动不会包含在内。
|
|
210
|
+
|
|
126
211
|
## 贡献与支持
|
|
127
212
|
|
|
128
213
|
如需更多帮助或贡献,请提交 Issue 或 PR。
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'fastlane/plugin/fastci/helper/fastci_zealot_helper'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Actions
|
|
5
|
+
# 查询 iOS 应用已上传版本,是否跳过后续打包由调用方决定。
|
|
6
|
+
class CheckZealotVersionAction < ZealotVersionCheckAction
|
|
7
|
+
extend Fastlane::Helper::FastciZealotHelper
|
|
8
|
+
|
|
9
|
+
def self.run(params)
|
|
10
|
+
validate_zealot_connection!(zealot_parameters(params))
|
|
11
|
+
[
|
|
12
|
+
SharedValues::ZEALOT_VERSION_EXISTED,
|
|
13
|
+
SharedValues::ZEAALOT_ERROR_MESSAGE,
|
|
14
|
+
SharedValues::ZEALOT_LATEST_RELEASE_ID,
|
|
15
|
+
SharedValues::ZEALOT_LATEST_RELEASE_VERSION,
|
|
16
|
+
SharedValues::ZEALOT_LATEST_VERSION,
|
|
17
|
+
SharedValues::ZEALOT_LATEST_RELEASE_URL,
|
|
18
|
+
SharedValues::ZEALOT_LATEST_INSTALL_URL,
|
|
19
|
+
SharedValues::ZEALOT_LATEST_QRCODE_URL,
|
|
20
|
+
SharedValues::ZEALOT_LATEST_CONTEXT
|
|
21
|
+
].each { |key| Actions.lane_context.delete(key) }
|
|
22
|
+
|
|
23
|
+
response = check_app_version(params)
|
|
24
|
+
# 上游非终止模式在网络错误时返回 false,不能继续读取 response.status。
|
|
25
|
+
return nil unless response
|
|
26
|
+
|
|
27
|
+
unless [200, 404].include?(response.status) && response.body.is_a?(Hash)
|
|
28
|
+
show_error("Zealot 版本查询失败(HTTP #{response.status})", params[:fail_on_error])
|
|
29
|
+
return nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
parse_response(response, params[:fail_on_error])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.available_options
|
|
36
|
+
zealot_options(ZealotVersionCheckAction)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.description
|
|
40
|
+
'按 Bundle ID 与版本号或 Git commit 查询 Zealot,返回是否已存在'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.example_code
|
|
44
|
+
['check_zealot_version(bundle_id: "com.example.app", release_version: "1.0", build_version: "1")']
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.is_supported?(platform)
|
|
48
|
+
platform == :ios
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -8,38 +8,43 @@ module Fastlane
|
|
|
8
8
|
# 打包
|
|
9
9
|
class PackageAction < Action
|
|
10
10
|
def self.run(params)
|
|
11
|
-
|
|
12
11
|
# 入参配置
|
|
13
|
-
configuration = params[:configuration] ||
|
|
14
|
-
export_method = params[:export_method] ||
|
|
12
|
+
configuration = params[:configuration] || 'Debug'
|
|
13
|
+
export_method = params[:export_method] || 'development'
|
|
15
14
|
build = params[:build] || nil
|
|
16
15
|
version = params[:version] || nil
|
|
17
16
|
is_analyze_swiftlint = params[:is_analyze_swiftlint] || false
|
|
18
17
|
is_detect_duplicity_code = params[:is_detect_duplicity_code] || false
|
|
19
18
|
is_detect_unused_code = params[:is_detect_unused_code] || false
|
|
20
19
|
is_detect_unused_image = params[:is_detect_unused_image] || false
|
|
21
|
-
release_notes = params[:release_notes] ||
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
release_notes = params[:release_notes] || ''
|
|
21
|
+
configuration = 'Release' if %w[app-store testFlight].include?(export_method)
|
|
22
|
+
is_notice_dingding = params[:is_notice_dingding].nil? ? true : params[:is_notice_dingding]
|
|
23
|
+
# 统一发送钉钉消息匿名函数
|
|
24
|
+
send_dingding_notice = lambda do |text|
|
|
25
|
+
if is_notice_dingding
|
|
26
|
+
DingdingHelper.sendMarkdown(text)
|
|
27
|
+
else
|
|
28
|
+
UI.message('*************| 跳过钉钉消息通知(is_notice_dingding=false)|*************')
|
|
29
|
+
end
|
|
24
30
|
end
|
|
25
|
-
|
|
31
|
+
send_dingding_notice.call('测试一下')
|
|
26
32
|
# 清理上一次的打包缓存
|
|
27
33
|
FileUtils.rm_rf(Dir.glob("#{Constants.BUILD_LOG_DIR}/*"))
|
|
28
34
|
FileUtils.rm_rf(Dir.glob("#{Constants.IPA_OUTPUT_DIR}/*"))
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
|
|
36
|
+
# 非自动更新模式下,安装证书和 provisioningProfile
|
|
37
|
+
unless Environment.is_auto_update_provisioning
|
|
38
|
+
other_action.install_certificate
|
|
39
|
+
other_action.install_profile
|
|
40
|
+
end
|
|
34
41
|
|
|
35
42
|
scheme = params[:scheme] || Environment.scheme
|
|
36
43
|
|
|
37
44
|
# 更改项目version
|
|
38
45
|
if CommonHelper.is_validate_string(version)
|
|
39
46
|
increment_options = { version_number: version }
|
|
40
|
-
if CommonHelper.is_validate_string(Environment.project)
|
|
41
|
-
increment_options[:xcodeproj] = Environment.project
|
|
42
|
-
end
|
|
47
|
+
increment_options[:xcodeproj] = Environment.project if CommonHelper.is_validate_string(Environment.project)
|
|
43
48
|
other_action.increment_version_number(increment_options)
|
|
44
49
|
end
|
|
45
50
|
|
|
@@ -47,45 +52,43 @@ module Fastlane
|
|
|
47
52
|
other_action.update_build_number(
|
|
48
53
|
build: build
|
|
49
54
|
)
|
|
50
|
-
time = Time.new.strftime(
|
|
51
|
-
|
|
55
|
+
time = Time.new.strftime('%Y%m%d%H%M')
|
|
56
|
+
|
|
52
57
|
# 获取版本号
|
|
53
58
|
version_options = { target: scheme }
|
|
54
|
-
if CommonHelper.is_validate_string(Environment.project)
|
|
55
|
-
version_options[:xcodeproj] = Environment.project
|
|
56
|
-
end
|
|
59
|
+
version_options[:xcodeproj] = Environment.project if CommonHelper.is_validate_string(Environment.project)
|
|
57
60
|
version = other_action.get_version_number(version_options)
|
|
58
|
-
|
|
61
|
+
|
|
59
62
|
# 获取 build 号
|
|
60
63
|
build_options = {}
|
|
61
|
-
if CommonHelper.is_validate_string(Environment.project)
|
|
62
|
-
build_options[:xcodeproj] = Environment.project
|
|
63
|
-
end
|
|
64
|
+
build_options[:xcodeproj] = Environment.project if CommonHelper.is_validate_string(Environment.project)
|
|
64
65
|
build = other_action.get_build_number(build_options)
|
|
65
66
|
# 生成ipa包的名字格式
|
|
66
67
|
ipaName = "#{scheme}_#{export_method}_#{version}_#{build}.ipa"
|
|
67
|
-
|
|
68
|
+
|
|
68
69
|
# 获取 Extension 的 Bundle ID(可能有多个,用逗号分隔)
|
|
69
70
|
extension_bundle_ids = Environment.extension_bundle_ids
|
|
70
71
|
extension_profile_names = []
|
|
71
72
|
# profile 名字
|
|
72
|
-
profile_name =
|
|
73
|
+
profile_name = ''
|
|
73
74
|
|
|
74
75
|
case export_method
|
|
75
|
-
when
|
|
76
|
+
when 'development'
|
|
76
77
|
profile_name = Environment.provisioningProfiles_development
|
|
77
78
|
extension_profile_names = Environment.extension_profiles_development
|
|
78
|
-
when
|
|
79
|
+
when 'ad-hoc'
|
|
79
80
|
profile_name = Environment.provisioningProfiles_adhoc
|
|
80
81
|
extension_profile_names = Environment.extension_profiles_adhoc
|
|
81
|
-
when
|
|
82
|
+
when 'app-store', 'testFlight'
|
|
82
83
|
profile_name = Environment.provisioningProfiles_appstore
|
|
83
84
|
extension_profile_names = Environment.extension_profiles_appstore
|
|
84
85
|
else
|
|
85
86
|
raise "Unsupported export method: #{export_method}"
|
|
86
87
|
end
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
UI.message('*************| 开始打包 |*************')
|
|
90
|
+
|
|
91
|
+
# 组装 provisioningProfiles
|
|
89
92
|
provisioningProfiles_map = {
|
|
90
93
|
"#{Environment.bundleID}" => "#{profile_name}"
|
|
91
94
|
}
|
|
@@ -93,11 +96,9 @@ module Fastlane
|
|
|
93
96
|
provisioningProfiles_map[ext_bundle_id.strip] = extension_profile_names[idx]&.strip
|
|
94
97
|
end
|
|
95
98
|
|
|
96
|
-
UI.message("*************| 开始打包 |*************")
|
|
97
|
-
|
|
98
99
|
# 对于 testFlight,使用 app-store 方法
|
|
99
|
-
gym_method = export_method ==
|
|
100
|
-
|
|
100
|
+
gym_method = export_method == 'testFlight' ? 'app-store' : export_method
|
|
101
|
+
|
|
101
102
|
gym_options = {
|
|
102
103
|
clean: true,
|
|
103
104
|
silent: true,
|
|
@@ -120,11 +121,11 @@ module Fastlane
|
|
|
120
121
|
|
|
121
122
|
other_action.gym(gym_options)
|
|
122
123
|
|
|
123
|
-
UI.message(
|
|
124
|
+
UI.message('*************| 打包完成 |*************')
|
|
124
125
|
|
|
125
|
-
UI.message(
|
|
126
|
+
UI.message('*************| 复制打包产物 |*************')
|
|
126
127
|
# 定义桌面路径
|
|
127
|
-
desktop_path = File.expand_path(
|
|
128
|
+
desktop_path = File.expand_path('~/Desktop')
|
|
128
129
|
output_path = File.join(desktop_path, "BuildOutput_#{scheme}")
|
|
129
130
|
target_path = File.join(output_path, "#{build}")
|
|
130
131
|
FileUtils.mkdir_p(target_path)
|
|
@@ -140,20 +141,20 @@ module Fastlane
|
|
|
140
141
|
|
|
141
142
|
ipa_path = "#{Constants.IPA_OUTPUT_DIR}/#{ipaName}"
|
|
142
143
|
|
|
143
|
-
if gym_method ==
|
|
144
|
+
if gym_method == 'app-store'
|
|
144
145
|
notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-打包完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
|
|
145
|
-
|
|
146
|
+
send_dingding_notice.call(notiText)
|
|
146
147
|
|
|
147
148
|
if CommonHelper.is_validate_string(Environment.connect_key_id) && CommonHelper.is_validate_string(Environment.connect_issuer_id)
|
|
148
149
|
# 根据 export_method 决定是否为 TestFlight
|
|
149
|
-
is_test_flight = export_method ==
|
|
150
|
-
|
|
150
|
+
is_test_flight = export_method == 'testFlight'
|
|
151
|
+
|
|
151
152
|
other_action.upload_store(
|
|
152
153
|
release_notes: release_notes,
|
|
153
154
|
isTestFlight: is_test_flight
|
|
154
155
|
)
|
|
155
156
|
notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-上传完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
|
|
156
|
-
|
|
157
|
+
send_dingding_notice.call(notiText)
|
|
157
158
|
end
|
|
158
159
|
else
|
|
159
160
|
# 钉钉通知
|
|
@@ -161,8 +162,8 @@ module Fastlane
|
|
|
161
162
|
|
|
162
163
|
# 上传蒲公英
|
|
163
164
|
if CommonHelper.is_validate_string(Environment.pgy_api_key)
|
|
164
|
-
pgy_upload_info = other_action.upload_pgy
|
|
165
|
-
qrCode = pgy_upload_info[
|
|
165
|
+
pgy_upload_info = other_action.upload_pgy
|
|
166
|
+
qrCode = pgy_upload_info['buildQRCodeURL']
|
|
166
167
|
|
|
167
168
|
if CommonHelper.is_validate_string(qrCode)
|
|
168
169
|
notiText << "\n\n⬇️⬇️⬇️ 扫码安装 ⬇️⬇️⬇️\n\n\n密码: #{Environment.pgy_password}\n"
|
|
@@ -181,43 +182,55 @@ module Fastlane
|
|
|
181
182
|
end
|
|
182
183
|
end
|
|
183
184
|
|
|
184
|
-
|
|
185
|
+
# 上传 Zealot
|
|
186
|
+
if CommonHelper.is_validate_string(Environment.zealot_token)
|
|
187
|
+
zealot_upload_info = other_action.upload_zealot(
|
|
188
|
+
file: ipa_path,
|
|
189
|
+
changelog: params[:changelog]
|
|
190
|
+
)
|
|
191
|
+
# dSYM 仅在 IPA 上传成功且显式开启时上传。
|
|
192
|
+
if zealot_upload_info && params[:is_upload_zealot_dsym]
|
|
193
|
+
other_action.upload_zealot_dsym
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
send_dingding_notice.call(notiText)
|
|
185
198
|
end
|
|
186
199
|
|
|
187
200
|
# Sentry 上传 dSYM
|
|
188
|
-
if CommonHelper.is_validate_string(Environment.sentry_auth_token)
|
|
189
|
-
other_action.sentry_upload_dsym
|
|
201
|
+
if CommonHelper.is_validate_string(Environment.sentry_auth_token)
|
|
202
|
+
other_action.sentry_upload_dsym
|
|
190
203
|
else
|
|
191
|
-
UI.message(
|
|
204
|
+
UI.message('*************| 未配置 Sentry 跳过 dSYM 上传 |*************')
|
|
192
205
|
end
|
|
193
206
|
|
|
194
207
|
# 代码分析
|
|
195
|
-
if is_analyze_swiftlint && gym_method !=
|
|
208
|
+
if is_analyze_swiftlint && gym_method != 'app-store'
|
|
196
209
|
other_action.analyze_swiftlint(
|
|
197
210
|
is_from_package: true,
|
|
198
211
|
configuration: configuration
|
|
199
212
|
)
|
|
200
213
|
# 结果复制到桌面
|
|
201
214
|
FileUtils.cp(SWIFTLINT_ANALYZE_HTML_FILE, target_path)
|
|
202
|
-
UI.message(
|
|
215
|
+
UI.message('*************| 代码分析完成 |*************')
|
|
203
216
|
else
|
|
204
|
-
UI.message(
|
|
217
|
+
UI.message('*************| 跳过代码分析 |*************')
|
|
205
218
|
end
|
|
206
219
|
|
|
207
220
|
# 重复代码检查
|
|
208
|
-
if is_detect_duplicity_code && gym_method !=
|
|
221
|
+
if is_detect_duplicity_code && gym_method != 'app-store'
|
|
209
222
|
other_action.detect_duplicity_code(
|
|
210
223
|
is_all: true
|
|
211
224
|
)
|
|
212
225
|
# 结果复制到桌面
|
|
213
226
|
FileUtils.cp(DUPLICITY_CODE_HTML_FILE, target_path)
|
|
214
|
-
UI.message(
|
|
227
|
+
UI.message('*************| 重复代码检查完成 |*************')
|
|
215
228
|
else
|
|
216
|
-
UI.message(
|
|
229
|
+
UI.message('*************| 跳过重复代码检查 |*************')
|
|
217
230
|
end
|
|
218
231
|
|
|
219
232
|
# 无用代码检查
|
|
220
|
-
if is_detect_unused_code && gym_method !=
|
|
233
|
+
if is_detect_unused_code && gym_method != 'app-store'
|
|
221
234
|
other_action.detect_unused_code(
|
|
222
235
|
scheme: scheme,
|
|
223
236
|
is_from_package: true,
|
|
@@ -225,127 +238,138 @@ module Fastlane
|
|
|
225
238
|
)
|
|
226
239
|
# 结果复制到桌面
|
|
227
240
|
FileUtils.cp(Constants.UNUSED_CODE_HTML_FILE, target_path)
|
|
228
|
-
UI.message(
|
|
241
|
+
UI.message('*************| 无用代码检查完成 |*************')
|
|
229
242
|
else
|
|
230
|
-
UI.message(
|
|
243
|
+
UI.message('*************| 跳过无用代码检查 |*************')
|
|
231
244
|
end
|
|
232
245
|
|
|
233
246
|
# 无用图片检查
|
|
234
|
-
if is_detect_unused_image && gym_method !=
|
|
235
|
-
other_action.detect_unused_image
|
|
247
|
+
if is_detect_unused_image && gym_method != 'app-store'
|
|
248
|
+
other_action.detect_unused_image
|
|
236
249
|
# 结果复制到桌面
|
|
237
250
|
FileUtils.cp(Constants.UNUSED_IMAGE_HTML_FILE, target_path)
|
|
238
|
-
UI.message(
|
|
251
|
+
UI.message('*************| 无用图片检查完成 |*************')
|
|
239
252
|
else
|
|
240
|
-
UI.message(
|
|
253
|
+
UI.message('*************| 跳过未使用图片检查 |*************')
|
|
241
254
|
end
|
|
242
255
|
|
|
243
256
|
if is_analyze_swiftlint ||
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
257
|
+
is_detect_duplicity_code ||
|
|
258
|
+
is_detect_unused_code ||
|
|
259
|
+
is_detect_unused_image
|
|
247
260
|
# 钉钉通知
|
|
248
261
|
notiText = "🚀🚀🚀🚀🚀🚀\n\n#{scheme}-iOS-代码检查完成\n\n#{version}_#{build}_#{export_method}\n\n🚀🚀🚀🚀🚀🚀"
|
|
249
|
-
|
|
262
|
+
send_dingding_notice.call(notiText)
|
|
250
263
|
else
|
|
251
|
-
UI.message(
|
|
264
|
+
UI.message('*************| 跳过代码检查 |*************')
|
|
252
265
|
end
|
|
253
266
|
|
|
254
|
-
UI.message(
|
|
267
|
+
UI.message('*************| 脚本完成 |*************')
|
|
255
268
|
end
|
|
256
269
|
|
|
257
270
|
def self.description
|
|
258
|
-
|
|
271
|
+
'打包'
|
|
259
272
|
end
|
|
260
273
|
|
|
261
274
|
def self.available_options
|
|
262
275
|
[
|
|
276
|
+
FastlaneCore::ConfigItem.new(
|
|
277
|
+
key: :is_upload_zealot_dsym,
|
|
278
|
+
env_name: 'ZEALOT_UPLOAD_DSYM',
|
|
279
|
+
description: 'IPA 上传 Zealot 成功后继续上传 iOS dSYM',
|
|
280
|
+
optional: true,
|
|
281
|
+
default_value: false,
|
|
282
|
+
type: Boolean
|
|
283
|
+
),
|
|
263
284
|
FastlaneCore::ConfigItem.new(
|
|
264
285
|
key: :scheme,
|
|
265
|
-
description:
|
|
286
|
+
description: '不采取默认配置,自定义 `scheme` 名称',
|
|
266
287
|
optional: true,
|
|
267
288
|
default_value: nil,
|
|
268
289
|
type: String
|
|
269
290
|
),
|
|
270
291
|
FastlaneCore::ConfigItem.new(
|
|
271
292
|
key: :configuration,
|
|
272
|
-
description:
|
|
293
|
+
description: '编译环境 Release or Debug',
|
|
273
294
|
optional: true,
|
|
274
|
-
default_value:
|
|
295
|
+
default_value: 'Debug',
|
|
275
296
|
type: String,
|
|
276
297
|
verify_block: proc do |value|
|
|
277
|
-
valid_params = [
|
|
278
|
-
unless valid_params.include?(value)
|
|
279
|
-
UI.user_error!("无效的编译环境: #{value}。支持的环境: #{valid_params.join(', ')}")
|
|
280
|
-
end
|
|
298
|
+
valid_params = %w[Release Debug]
|
|
299
|
+
UI.user_error!("无效的编译环境: #{value}。支持的环境: #{valid_params.join(', ')}") unless valid_params.include?(value)
|
|
281
300
|
end
|
|
282
301
|
),
|
|
283
302
|
FastlaneCore::ConfigItem.new(
|
|
284
303
|
key: :export_method,
|
|
285
|
-
description:
|
|
304
|
+
description: '打包方式 ad-hoc, enterprise, app-store, development, testFlight',
|
|
286
305
|
optional: true,
|
|
287
|
-
default_value:
|
|
306
|
+
default_value: 'development',
|
|
288
307
|
type: String,
|
|
289
308
|
verify_block: proc do |value|
|
|
290
|
-
valid_params = [
|
|
291
|
-
unless valid_params.include?(value)
|
|
292
|
-
UI.user_error!("无效的打包方式: #{value}。支持的方式: #{valid_params.join(', ')}")
|
|
293
|
-
end
|
|
309
|
+
valid_params = %w[ad-hoc enterprise app-store development testFlight]
|
|
310
|
+
UI.user_error!("无效的打包方式: #{value}。支持的方式: #{valid_params.join(', ')}") unless valid_params.include?(value)
|
|
294
311
|
end
|
|
295
312
|
),
|
|
296
313
|
FastlaneCore::ConfigItem.new(
|
|
297
314
|
key: :version,
|
|
298
|
-
description:
|
|
315
|
+
description: '自定义 `version`。在 Xcode13 之后创建的项目,不再支持脚本修改。需要兼容请在 Build settings 中将 GENERATE_INFOPLIST_FILE 设置为 NO',
|
|
299
316
|
optional: true,
|
|
300
317
|
default_value: nil,
|
|
301
318
|
type: String
|
|
302
319
|
),
|
|
303
320
|
FastlaneCore::ConfigItem.new(
|
|
304
321
|
key: :build,
|
|
305
|
-
description:
|
|
322
|
+
description: '不采取自动更新,自定义 `build` 号',
|
|
306
323
|
optional: true,
|
|
307
324
|
default_value: nil,
|
|
308
325
|
type: String
|
|
309
326
|
),
|
|
310
327
|
FastlaneCore::ConfigItem.new(
|
|
311
328
|
key: :is_analyze_swiftlint,
|
|
312
|
-
description:
|
|
329
|
+
description: '是否代码分析',
|
|
313
330
|
optional: true,
|
|
314
331
|
default_value: false,
|
|
315
332
|
type: Boolean
|
|
316
333
|
),
|
|
317
334
|
FastlaneCore::ConfigItem.new(
|
|
318
335
|
key: :is_detect_duplicity_code,
|
|
319
|
-
description:
|
|
336
|
+
description: '是否检查重复代码',
|
|
320
337
|
optional: true,
|
|
321
338
|
default_value: false,
|
|
322
339
|
type: Boolean
|
|
323
340
|
),
|
|
324
341
|
FastlaneCore::ConfigItem.new(
|
|
325
342
|
key: :is_detect_unused_code,
|
|
326
|
-
description:
|
|
343
|
+
description: '是否检查无用代码',
|
|
327
344
|
optional: true,
|
|
328
345
|
default_value: false,
|
|
329
346
|
type: Boolean
|
|
330
347
|
),
|
|
331
348
|
FastlaneCore::ConfigItem.new(
|
|
332
349
|
key: :is_detect_unused_image,
|
|
333
|
-
description:
|
|
350
|
+
description: '是否检查无用图片',
|
|
334
351
|
optional: true,
|
|
335
352
|
default_value: false,
|
|
336
353
|
type: Boolean
|
|
337
354
|
),
|
|
338
355
|
FastlaneCore::ConfigItem.new(
|
|
339
356
|
key: :changelog,
|
|
340
|
-
description:
|
|
357
|
+
description: '更新日志',
|
|
341
358
|
optional: true,
|
|
342
359
|
type: String
|
|
343
360
|
),
|
|
344
361
|
FastlaneCore::ConfigItem.new(
|
|
345
362
|
key: :release_notes,
|
|
346
|
-
description:
|
|
363
|
+
description: '更新文案, 格式为 { "zh-Hans": "修复问题", "en-US": "bugfix"} JSON 字符串',
|
|
347
364
|
optional: true,
|
|
348
365
|
type: String
|
|
366
|
+
),
|
|
367
|
+
FastlaneCore::ConfigItem.new(
|
|
368
|
+
key: :is_notice_dingding,
|
|
369
|
+
description: '是否通知钉钉(默认true, 优先级高于DINGDING_TOKEN)',
|
|
370
|
+
optional: true,
|
|
371
|
+
default_value: true,
|
|
372
|
+
type: Boolean
|
|
349
373
|
)
|
|
350
374
|
]
|
|
351
375
|
end
|
|
@@ -357,7 +381,6 @@ module Fastlane
|
|
|
357
381
|
def self.category
|
|
358
382
|
:building
|
|
359
383
|
end
|
|
360
|
-
|
|
361
384
|
end
|
|
362
385
|
end
|
|
363
|
-
end
|
|
386
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'fastlane/plugin/fastci/helper/fastci_zealot_helper'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Actions
|
|
5
|
+
# 手动同步 Apple 开发者账号中的 iOS 设备,不挂入自动打包流程。
|
|
6
|
+
class SyncZealotDevicesAction < ZealotSyncDevicesAction
|
|
7
|
+
extend Fastlane::Helper::FastciZealotHelper
|
|
8
|
+
|
|
9
|
+
def self.run(params)
|
|
10
|
+
validate_zealot_connection!(zealot_parameters(params))
|
|
11
|
+
Actions.lane_context.delete(SharedValues::ZEAALOT_ERROR_MESSAGE)
|
|
12
|
+
devices = fetch_ios_devices(params)
|
|
13
|
+
print_table(build_table_data(params, devices), title: 'sync_zealot_devices')
|
|
14
|
+
|
|
15
|
+
# 沿用官方的设备上传协议,按实际 HTTP 结果统计,避免失败被计为成功。
|
|
16
|
+
failed = devices.count { |device| !sync_ios_device(params, device) }
|
|
17
|
+
result = { total: devices.size, succeeded: devices.size - failed, failed: failed }
|
|
18
|
+
UI.message("Zealot iOS 设备同步:成功 #{result[:succeeded]},失败 #{failed}")
|
|
19
|
+
result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.fetch_ios_devices(params)
|
|
23
|
+
require 'spaceship'
|
|
24
|
+
|
|
25
|
+
token = Spaceship::ConnectAPI::Token.from(hash: params[:api_key], filepath: params[:api_key_path])
|
|
26
|
+
if token
|
|
27
|
+
Spaceship::ConnectAPI.token = token
|
|
28
|
+
return Spaceship::ConnectAPI::Device.all(filter: { platform: 'IOS' })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
credentials = CredentialsManager::AccountManager.new(user: params[:username])
|
|
32
|
+
Spaceship.login(credentials.user, credentials.password)
|
|
33
|
+
Spaceship.select_team
|
|
34
|
+
Spaceship::Device.all(mac: false)
|
|
35
|
+
end
|
|
36
|
+
private_class_method :fetch_ios_devices
|
|
37
|
+
|
|
38
|
+
def self.sync_ios_device(params, device)
|
|
39
|
+
response = sync_deivce(params, device)
|
|
40
|
+
return true if response.success?
|
|
41
|
+
|
|
42
|
+
show_error("Zealot 设备同步失败(HTTP #{response.status})", params[:fail_on_error])
|
|
43
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => error
|
|
44
|
+
show_error("Zealot 设备同步请求失败:#{error.class}", params[:fail_on_error])
|
|
45
|
+
end
|
|
46
|
+
private_class_method :sync_ios_device
|
|
47
|
+
|
|
48
|
+
def self.available_options
|
|
49
|
+
zealot_options(ZealotSyncDevicesAction, excluding: [:platform])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.description
|
|
53
|
+
'同步 Apple 开发者账号中的 iOS 设备到 Zealot'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.example_code
|
|
57
|
+
['sync_zealot_devices(api_key_path: "./app_store_connect_api_key.json")']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.is_supported?(platform)
|
|
61
|
+
platform == :ios
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'fastlane/plugin/fastci/helper/fastci_zealot_helper'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Actions
|
|
5
|
+
# iOS IPA 上传:沿用官方传输与结果解析,避免复制 Zealot HTTP 协议。
|
|
6
|
+
class UploadZealotAction < ZealotAction
|
|
7
|
+
extend Fastlane::Helper::FastciZealotHelper
|
|
8
|
+
|
|
9
|
+
def self.run(params)
|
|
10
|
+
validate_zealot_connection!(zealot_parameters(params))
|
|
11
|
+
UI.user_error!('请指定 IPA 文件或先执行 gym/package') if params[:file].to_s.empty?
|
|
12
|
+
|
|
13
|
+
# 同一 lane 可多次上传,失败时不能返回上一次上传的地址。
|
|
14
|
+
output.each { |key, _description| Actions.lane_context.delete(key.to_sym) }
|
|
15
|
+
super(params)
|
|
16
|
+
return nil unless Actions.lane_context[SharedValues::ZEALOT_RELEASE_ID]
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
app_id: Actions.lane_context[SharedValues::ZEALOT_APP_ID],
|
|
20
|
+
release_id: Actions.lane_context[SharedValues::ZEALOT_RELEASE_ID],
|
|
21
|
+
release_url: Actions.lane_context[SharedValues::ZEALOT_RELEASE_URL],
|
|
22
|
+
install_url: Actions.lane_context[SharedValues::ZEALOT_INSTALL_URL],
|
|
23
|
+
qrcode_url: Actions.lane_context[SharedValues::ZEALOT_QRCODE_URL]
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.available_options
|
|
28
|
+
options = zealot_options(ZealotAction, excluding: [:file])
|
|
29
|
+
options << FastlaneCore::ConfigItem.new(
|
|
30
|
+
key: :file,
|
|
31
|
+
env_name: 'ZEALOT_FILE',
|
|
32
|
+
description: 'iOS IPA 路径,默认使用本次 gym 的产物',
|
|
33
|
+
optional: true,
|
|
34
|
+
default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH],
|
|
35
|
+
type: String,
|
|
36
|
+
verify_block: proc do |value|
|
|
37
|
+
unless File.file?(value) && File.extname(value).casecmp('.ipa').zero?
|
|
38
|
+
UI.user_error!("不是有效的 IPA 文件:#{value}")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
)
|
|
42
|
+
options
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.description
|
|
46
|
+
'上传 iOS IPA 到 Zealot,返回应用、版本和下载地址'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.example_code
|
|
50
|
+
['upload_zealot(file: "./App.ipa", changelog: "iOS 更新说明")']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.is_supported?(platform)
|
|
54
|
+
platform == :ios
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'fastlane/plugin/fastci/helper/fastci_zealot_helper'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Actions
|
|
5
|
+
# 固定走官方 iOS dSYM 流程,不暴露 Android 或 macOS 参数。
|
|
6
|
+
class UploadZealotDsymAction < ZealotDebugFileAction
|
|
7
|
+
extend Fastlane::Helper::FastciZealotHelper
|
|
8
|
+
|
|
9
|
+
def self.run(params)
|
|
10
|
+
values = zealot_parameters(params)
|
|
11
|
+
validate_zealot_connection!(values)
|
|
12
|
+
values[:platform] = 'ios'
|
|
13
|
+
values[:zip_file] ||= Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH] unless values[:path]
|
|
14
|
+
values[:path] ||= Actions.lane_context[SharedValues::XCODEBUILD_ARCHIVE] unless values[:zip_file]
|
|
15
|
+
|
|
16
|
+
unless values[:zip_file] || values[:path]
|
|
17
|
+
UI.user_error!('请指定 dSYM zip_file、xcarchive path,或先执行 gym/package')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if values[:zip_file] && !File.file?(values[:zip_file])
|
|
21
|
+
UI.user_error!("dSYM 压缩文件不存在:#{values[:zip_file]}")
|
|
22
|
+
end
|
|
23
|
+
if values[:path] && !File.directory?(values[:path])
|
|
24
|
+
UI.user_error!("Xcode archive 不存在:#{values[:path]}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Actions.lane_context.delete(SharedValues::ZEAALOT_ERROR_MESSAGE)
|
|
28
|
+
super(FastlaneCore::Configuration.create(ZealotDebugFileAction.available_options, values))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# 上游只检查响应中的 error 字段;非成功 HTTP 状态不能计为上传成功。
|
|
32
|
+
def self.parse_response(response, upload_url, fail_on_error)
|
|
33
|
+
return unless response
|
|
34
|
+
|
|
35
|
+
unless response.success? && response.body.is_a?(Hash)
|
|
36
|
+
return show_error("Zealot dSYM 上传失败(HTTP #{response.status})", fail_on_error)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
super
|
|
40
|
+
end
|
|
41
|
+
private_class_method :parse_response
|
|
42
|
+
|
|
43
|
+
def self.available_options
|
|
44
|
+
zealot_options(
|
|
45
|
+
ZealotDebugFileAction,
|
|
46
|
+
excluding: [:platform, :android_build_type, :android_flavor]
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.description
|
|
51
|
+
'上传 iOS dSYM 到 Zealot,支持 zip_file、xcarchive 或本次 gym 产物'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.example_code
|
|
55
|
+
['upload_zealot_dsym(zip_file: "./App.app.dSYM.zip")']
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.is_supported?(platform)
|
|
59
|
+
platform == :ios
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -91,6 +91,17 @@ module Fastlane
|
|
|
91
91
|
ENV['FIR_SWITCH_QINIU'] == "true"
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
+
# Zealot 配置;可选上传渠道,未配置时不影响现有打包流程。
|
|
95
|
+
def self.zealot_endpoint
|
|
96
|
+
ENV['ZEALOT_ENDPOINT']
|
|
97
|
+
end
|
|
98
|
+
def self.zealot_token
|
|
99
|
+
ENV['ZEALOT_TOKEN']
|
|
100
|
+
end
|
|
101
|
+
def self.zealot_channel_key
|
|
102
|
+
ENV['ZEALOT_CHANNEL_KEY']
|
|
103
|
+
end
|
|
104
|
+
|
|
94
105
|
# 钉钉配置
|
|
95
106
|
def self.dingdingToken
|
|
96
107
|
ENV['DINGDING_TOKEN']
|
|
@@ -112,4 +123,4 @@ module Fastlane
|
|
|
112
123
|
|
|
113
124
|
end
|
|
114
125
|
end
|
|
115
|
-
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'fastlane/plugin/zealot'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Helper
|
|
5
|
+
# 复用官方 Action 的协议与参数,仅收口 FastCI 的 iOS 边界和日志脱敏。
|
|
6
|
+
module FastciZealotHelper
|
|
7
|
+
def zealot_options(action, excluding: [])
|
|
8
|
+
options = action.available_options.reject do |option|
|
|
9
|
+
excluding.include?(option.key) || option.key == :fail_on_error
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# 新增上传渠道默认明确报错,避免 CI 把失败当作上传完成。
|
|
13
|
+
options << FastlaneCore::ConfigItem.new(
|
|
14
|
+
key: :fail_on_error,
|
|
15
|
+
env_name: 'ZEALOT_FAIL_ON_ERROR',
|
|
16
|
+
description: 'Zealot 请求失败时终止当前任务',
|
|
17
|
+
optional: true,
|
|
18
|
+
default_value: true,
|
|
19
|
+
type: Boolean
|
|
20
|
+
)
|
|
21
|
+
options
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def zealot_parameters(params)
|
|
25
|
+
params.all_keys.each_with_object({}) do |key, values|
|
|
26
|
+
value = params[key]
|
|
27
|
+
values[key] = value unless value.nil?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate_zealot_connection!(values)
|
|
32
|
+
keys = [:endpoint, :token]
|
|
33
|
+
keys << :channel_key if values.key?(:channel_key)
|
|
34
|
+
keys.each do |key|
|
|
35
|
+
UI.user_error!("缺少 Zealot #{key}") if values[key].to_s.strip.empty?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# 官方部分 Action 未隐藏 token;只改变当前封装的输出,不修改上游全局实现。
|
|
40
|
+
def print_table(form, title: 'zealot', hidden_keys: [], remove_empty_value: true)
|
|
41
|
+
super(
|
|
42
|
+
form,
|
|
43
|
+
title: title,
|
|
44
|
+
hidden_keys: hidden_keys + [:token, :Token],
|
|
45
|
+
remove_empty_value: remove_empty_value
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane-plugin-fastci
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.30
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- watermelon
|
|
@@ -57,14 +57,28 @@ dependencies:
|
|
|
57
57
|
requirements:
|
|
58
58
|
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version:
|
|
60
|
+
version: 2.5.1
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version:
|
|
67
|
+
version: 2.5.1
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: fastlane-plugin-zealot
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: 1.0.1
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 1.0.1
|
|
68
82
|
email: watermelon_lp@163.com
|
|
69
83
|
executables: []
|
|
70
84
|
extensions: []
|
|
@@ -74,6 +88,7 @@ files:
|
|
|
74
88
|
- README.md
|
|
75
89
|
- lib/fastlane/plugin/fastci.rb
|
|
76
90
|
- lib/fastlane/plugin/fastci/actions/analyze_swiftlint_action.rb
|
|
91
|
+
- lib/fastlane/plugin/fastci/actions/check_zealot_version_action.rb
|
|
77
92
|
- lib/fastlane/plugin/fastci/actions/detect_duplicity_code_action.rb
|
|
78
93
|
- lib/fastlane/plugin/fastci/actions/detect_unused_code_action.rb
|
|
79
94
|
- lib/fastlane/plugin/fastci/actions/detect_unused_image_action.rb
|
|
@@ -81,14 +96,18 @@ files:
|
|
|
81
96
|
- lib/fastlane/plugin/fastci/actions/install_profile_action.rb
|
|
82
97
|
- lib/fastlane/plugin/fastci/actions/package_action.rb
|
|
83
98
|
- lib/fastlane/plugin/fastci/actions/sentry_upload_dsym.rb
|
|
99
|
+
- lib/fastlane/plugin/fastci/actions/sync_zealot_devices_action.rb
|
|
84
100
|
- lib/fastlane/plugin/fastci/actions/update_build_number_action.rb
|
|
85
101
|
- lib/fastlane/plugin/fastci/actions/upload_fir_action.rb
|
|
86
102
|
- lib/fastlane/plugin/fastci/actions/upload_pgy_action.rb
|
|
87
103
|
- lib/fastlane/plugin/fastci/actions/upload_store_action.rb
|
|
104
|
+
- lib/fastlane/plugin/fastci/actions/upload_zealot_action.rb
|
|
105
|
+
- lib/fastlane/plugin/fastci/actions/upload_zealot_dsym_action.rb
|
|
88
106
|
- lib/fastlane/plugin/fastci/helper/common_helper.rb
|
|
89
107
|
- lib/fastlane/plugin/fastci/helper/constants.rb
|
|
90
108
|
- lib/fastlane/plugin/fastci/helper/dingding_helper.rb
|
|
91
109
|
- lib/fastlane/plugin/fastci/helper/environment.rb
|
|
110
|
+
- lib/fastlane/plugin/fastci/helper/fastci_zealot_helper.rb
|
|
92
111
|
- lib/fastlane/plugin/fastci/helper/fir_helper.rb
|
|
93
112
|
- lib/fastlane/plugin/fastci/version.rb
|
|
94
113
|
- lib/fastlane/plugin/python/generate_duplicity_code_html.py
|
|
@@ -114,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
114
133
|
- !ruby/object:Gem::Version
|
|
115
134
|
version: '0'
|
|
116
135
|
requirements: []
|
|
117
|
-
rubygems_version:
|
|
136
|
+
rubygems_version: 4.0.23
|
|
118
137
|
specification_version: 4
|
|
119
138
|
summary: supports multiple functions such as packaging, uploading, and code detection.
|
|
120
139
|
test_files: []
|