fastlane-plugin-fastci 0.0.20 → 0.0.40
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 +310 -6
- data/lib/fastlane/plugin/fastci/actions/app_store_resources_action.rb +300 -0
- data/lib/fastlane/plugin/fastci/actions/check_zealot_version_action.rb +52 -0
- data/lib/fastlane/plugin/fastci/actions/package_action.rb +78 -9
- data/lib/fastlane/plugin/fastci/actions/sync_zealot_devices_action.rb +65 -0
- data/lib/fastlane/plugin/fastci/actions/upload_store_action.rb +116 -35
- 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/app_store_resources_helper.rb +436 -0
- data/lib/fastlane/plugin/fastci/helper/environment.rb +25 -1
- data/lib/fastlane/plugin/fastci/helper/fastci_zealot_helper.rb +51 -0
- data/lib/fastlane/plugin/fastci/version.rb +1 -1
- metadata +24 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5978da99fdc693c5d6f873bee51f791254b236e6eb92d9beaeea064ca730b52
|
|
4
|
+
data.tar.gz: 70cc23a65e930ee3df7359a10ae751544276fb64b0b9dd1db395033e7a12322b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4ec254de949a0c02e98985d29d2d77d958da26c6a4925ecc8c151c3d29c1faa3766a3f11e410d4211fc4c20b9cb3e91e45688958fe6b9ca2b3278f1f23cb6cb
|
|
7
|
+
data.tar.gz: bc29f33a3c238d6aa61f7d9500c7eb97969b19c63231e321a8758b2adb7df4c7468b978a7fc5bc3a9aa5d516aefd96ca66b83924dcd6bf06145258202469dfc4
|
data/README.md
CHANGED
|
@@ -25,14 +25,13 @@
|
|
|
25
25
|
|
|
26
26
|
## 使用方法
|
|
27
27
|
|
|
28
|
-
参考 [
|
|
28
|
+
参考 [Fastfile](fastlane/Fastfile),将[配置模板](fastlane/.env.default.example)复制为项目中的 `fastlane/.env.default`,再填写项目参数;
|
|
29
29
|
项目根目录新建 ` PACKAGE_FILE_FOLDER_NAME ` 配置对应名字文件夹,将描述文件、p12 证书、p8 密钥等文件放入该文件夹下;
|
|
30
30
|
然后终端进入项目根目录即可使用 ` fastlane `
|
|
31
31
|
|
|
32
|
-
如果是同一个 xcworkspace 多 xcodeproj
|
|
32
|
+
如果是同一个 xcworkspace 多 xcodeproj 的情况,可以采用多配置文件的方式。同样参考[配置模板](fastlane/.env.default.example),根据多个 xcodeproj 创建配置文件 ` .env.project1 `、` .env.project2 `;运行配置不保留 `.example` 后缀,名字也不能是 ` .env.project1.default `;
|
|
33
33
|
不同的配置文件配置不同的 ` PROJECT_NAME `;
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
使用本仓库示例 Fastfile 时,指定环境文件执行 `bundle exec fastlane ios ipaPackage --env project1`。
|
|
36
35
|
|
|
37
36
|
### 使用后会在项目根目录生成文件夹
|
|
38
37
|
|
|
@@ -53,6 +52,8 @@ fastlane_cache/ # 插件缓存文件夹
|
|
|
53
52
|
功能:自动编译并导出 ipa 包,支持多种打包方式和集成多项检查。
|
|
54
53
|
生成完的 ipa 会放在桌面上,非 ` app-store ` 配置了蒲公英或 fir 参数会自动上传蒲公英或 fir。` app-store ` 和 ` testFlight ` 配置了商店参数会自动上传商店。
|
|
55
54
|
配置了 Sentry 参数会自动上传符号表。
|
|
55
|
+
配置了 Zealot 参数的非商店包也可自动上传,详见下方 Zealot 配置。
|
|
56
|
+
App Store 元数据、截图和更新说明默认不上传,必须单独开启商店资源总开关并配置资源 JSON;详见 [App Store 元数据与截图](#app-store-resources)。TestFlight 不使用商店资源配置。
|
|
56
57
|
|
|
57
58
|
` build `: 不指定的话内部有递增逻辑,格式为 ` 20250905.15(日期+当天包的次数) `
|
|
58
59
|
|
|
@@ -70,8 +71,10 @@ package(
|
|
|
70
71
|
is_detect_duplicity_code: false, # 是否检测重复代码
|
|
71
72
|
is_detect_unused_code: false, # 是否检测未使用代码
|
|
72
73
|
is_detect_unused_image: false, # 是否检测未使用图片
|
|
73
|
-
changelog: options[:changelog], # fir 更新日志
|
|
74
|
-
|
|
74
|
+
changelog: options[:changelog], # fir / Zealot 更新日志
|
|
75
|
+
app_store_resources_enabled: options[:app_store_resources_enabled], # 总开关;未传时读取 APP_STORE_RESOURCES_ENABLED,默认 false
|
|
76
|
+
app_store_resources_config_path: options[:app_store_resources_config_path], # 未传时读取 APP_STORE_RESOURCES_CONFIG_PATH
|
|
77
|
+
release_notes: options[:release_notes], # JSON 字符串,例如 '{"zh-Hans":"修复问题","en-US":"Bug fixes"}';仅资源功能开启且上传 metadata 时生效
|
|
75
78
|
is_notice_dingding: options[:is_notice_dingding] # 配置钉钉token了,通过该参数控制是否发送通知
|
|
76
79
|
)
|
|
77
80
|
```
|
|
@@ -124,6 +127,307 @@ detect_unused_image(
|
|
|
124
127
|
|
|
125
128
|
---
|
|
126
129
|
|
|
130
|
+
<a id="app-store-resources"></a>
|
|
131
|
+
|
|
132
|
+
### 6. App Store 元数据与截图(配置驱动,仅 iOS)
|
|
133
|
+
|
|
134
|
+
通过独立 `app_store_resources` Action 管理商店名称、副标题、描述、关键词、更新说明、宣传文本、支持/隐私链接、分类、审核信息及截图,沿用 Fastlane 的 metadata 目录格式。也可以接入现有 `package` / `upload_store` 流程:先上传 IPA,再上传配置指定的资源,最后按需选择 Build、提交审核。
|
|
135
|
+
|
|
136
|
+
**商店资源总开关默认关闭,必须设置 `APP_STORE_RESOURCES_ENABLED=true`,或显式传入 `app_store_resources_enabled: true` 才能使用。** 只配置 JSON 路径、资源目录、`metadata_changed` 或 `release_notes` 均不会开启功能。关闭时,`package` / `upload_store` 仅上传 IPA,明确跳过元数据、截图和更新说明;独立 `app_store_resources` 直接跳过,不读取资源配置、不认证、不上传下载、不选择构建或提交审核。TestFlight 和测试包不使用商店资源流程。
|
|
137
|
+
|
|
138
|
+
| 入口 | 用途 | 开启后的配置要求 |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `package` | 打包并上传 IPA,再执行资源流程 | 必须提供 `app_store_resources_config_path`;自动传入本次 Bundle ID、版本和 Build |
|
|
141
|
+
| `upload_store` | 上传已有 gym 产物,再执行资源流程 | 必须提供 `app_store_resources_config_path`;需要选择构建时自行提供版本与 Build |
|
|
142
|
+
| `app_store_resources` | 独立更新商店资源,不上传 IPA | 使用 `config_path` 或直接传入资源参数 |
|
|
143
|
+
|
|
144
|
+
#### 配置与认证
|
|
145
|
+
|
|
146
|
+
将 [`fastlane/app_store_resources.example.json`](fastlane/app_store_resources.example.json) 复制到业务项目,例如 `fastlane/app_store_resources.json`,修改 Bundle ID、版本和资源路径。使用**扁平 JSON**;项目自有的嵌套 Jenkins 配置需要先转换为模板中的字段。
|
|
147
|
+
|
|
148
|
+
```dotenv
|
|
149
|
+
# 总开关,未设置或 false 时均不能使用商店资源功能。
|
|
150
|
+
APP_STORE_RESOURCES_ENABLED=true
|
|
151
|
+
# 相对路径以执行 Action 时的项目根目录为基准,不以 JSON 所在目录为基准。
|
|
152
|
+
APP_STORE_RESOURCES_CONFIG_PATH=fastlane/app_store_resources.json
|
|
153
|
+
|
|
154
|
+
# 认证方式一:App Store Connect API Key JSON(本机或 CI 密钥文件)。
|
|
155
|
+
APP_STORE_CONNECT_API_KEY_PATH=/secure/app-store-connect.json
|
|
156
|
+
|
|
157
|
+
# 认证方式二:沿用 CONNECT_KEY_ID、CONNECT_ISSUER_ID 和证书目录下的 P8。
|
|
158
|
+
# 可选 APP_STORE_CONNECT_P8_PATH=/secure/AuthKey_KEYID.p8 覆盖默认路径。
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| 环境变量 | 默认值 | 说明 |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `APP_STORE_RESOURCES_ENABLED` | `false` | 商店资源总开关;未设置与关闭效果相同 |
|
|
164
|
+
| `APP_STORE_RESOURCES_CONFIG_PATH` | 未设置 | 资源 JSON 路径;`package` / `upload_store` 开启资源功能后必填 |
|
|
165
|
+
| `APP_STORE_CONNECT_API_KEY_PATH` | 未设置 | 认证用 API Key JSON 路径,与资源 JSON 是两个不同文件 |
|
|
166
|
+
| `APP_STORE_CONNECT_P8_PATH` | 未设置 | 自定义 P8 路径,配合 `CONNECT_KEY_ID`、`CONNECT_ISSUER_ID` 使用;不配置时从 `PACKAGE_FILE_FOLDER_NAME/AuthKey_<KEY_ID>.p8` 读取 |
|
|
167
|
+
|
|
168
|
+
认证方式二的环境配置示例:
|
|
169
|
+
|
|
170
|
+
```dotenv
|
|
171
|
+
CONNECT_KEY_ID=your-key-id
|
|
172
|
+
CONNECT_ISSUER_ID=your-issuer-id
|
|
173
|
+
APP_STORE_CONNECT_P8_PATH=/secure/AuthKey_your-key-id.p8
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
使用 P8 方式时不设置 `APP_STORE_CONNECT_API_KEY_PATH`。资源 JSON 或显式参数中的认证优先,其次是环境中的 API Key JSON、已有 lane 的 API Key,最后使用 P8 配置。已有 API Key 可直接复用,无需每次重新创建。
|
|
177
|
+
|
|
178
|
+
资源配置示例:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"app_identifier": "com.example.app",
|
|
183
|
+
"app_version": "1.0.0",
|
|
184
|
+
"metadata_path": "fastlane/metadata",
|
|
185
|
+
"screenshots_path": "fastlane/screenshots",
|
|
186
|
+
"metadata_changed": true,
|
|
187
|
+
"screenshots_changed": false,
|
|
188
|
+
"upload_metadata_on_new_version": true,
|
|
189
|
+
"select_build": false,
|
|
190
|
+
"submit_for_review": false,
|
|
191
|
+
"automatic_release": false
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### 元数据与截图目录
|
|
196
|
+
|
|
197
|
+
元数据内容存放于文本文件,语言目录名与 App Store Connect 语言代码对应,例如:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
fastlane/metadata/
|
|
201
|
+
├── copyright.txt
|
|
202
|
+
├── primary_category.txt
|
|
203
|
+
├── review_information/notes.txt
|
|
204
|
+
├── zh-Hans/
|
|
205
|
+
│ ├── name.txt
|
|
206
|
+
│ ├── subtitle.txt
|
|
207
|
+
│ ├── description.txt
|
|
208
|
+
│ ├── keywords.txt
|
|
209
|
+
│ ├── promotional_text.txt
|
|
210
|
+
│ ├── support_url.txt
|
|
211
|
+
│ ├── privacy_url.txt
|
|
212
|
+
│ └── release_notes.txt
|
|
213
|
+
└── en-US/
|
|
214
|
+
├── description.txt
|
|
215
|
+
└── release_notes.txt
|
|
216
|
+
fastlane/screenshots/zh-Hans/1.png
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
只更新文案时设置 `metadata_changed=true`、`screenshots_changed=false`;只更新截图时设置 `metadata_changed=false`、`screenshots_changed=true`。如果还要禁止新版本自动补传文案,需同时设置 `upload_metadata_on_new_version=false`。上传的资源类别必须有非空目录,截图支持 `.png`、`.jpg`、`.jpeg`,图片格式和设备尺寸由 deliver 校验。
|
|
220
|
+
|
|
221
|
+
#### Action 与命令行调用
|
|
222
|
+
|
|
223
|
+
总开关开启后,在已有打包 lane 中配置资源路径即可使用;也可以显式传入开关和路径:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
package(
|
|
227
|
+
export_method: "app-store",
|
|
228
|
+
app_store_resources_enabled: true,
|
|
229
|
+
app_store_resources_config_path: "fastlane/app_store_resources.json"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# 只更新商店资源,不重新构建、不上传 IPA。
|
|
233
|
+
app_store_resources(
|
|
234
|
+
app_store_resources_enabled: true,
|
|
235
|
+
config_path: "fastlane/app_store_resources.json"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# 已有 gym 产物时,上传 IPA 后更新资源。
|
|
239
|
+
upload_store(
|
|
240
|
+
app_store_resources_enabled: true,
|
|
241
|
+
app_store_resources_config_path: "fastlane/app_store_resources.json"
|
|
242
|
+
)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
总开关只通过环境变量或 Action 参数配置,不放在资源 JSON 中;显式 Action 参数优先于环境变量,因此传 `app_store_resources_enabled: false` 可以关闭环境中已开启的功能。`package` / `upload_store` 开启后必须同时提供资源配置路径,否则报错;独立 Action 开启后也可直接传入资源参数。
|
|
246
|
+
|
|
247
|
+
使用本仓库示例 [Fastfile](fastlane/Fastfile) 时,可以在业务项目根目录运行以下命令。命令会执行实际上传,运行前应替换配置中的示例值并准备对应资源和认证文件。
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# 打包、上传 App Store IPA,再更新资源;开关、资源路径和认证读取环境文件。
|
|
251
|
+
bundle exec fastlane ios ipaPackage export_method:app-store
|
|
252
|
+
|
|
253
|
+
# 只更新商店资源;开关、资源路径和认证读取环境文件。
|
|
254
|
+
bundle exec fastlane ios appStoreResources
|
|
255
|
+
|
|
256
|
+
# 也可以在调用时明确开启,并为独立资源 lane 指定配置文件。
|
|
257
|
+
bundle exec fastlane ios appStoreResources app_store_resources_enabled:true config_path:fastlane/app_store_resources.json
|
|
258
|
+
|
|
259
|
+
# 本次仅上传 IPA,即使环境文件已开启资源功能也不更新资源。
|
|
260
|
+
bundle exec fastlane ios ipaPackage export_method:app-store app_store_resources_enabled:false
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
多项目环境可在命令后追加 `--env project1`。示例 lane 名是 `ipaPackage` 和 `appStoreResources`;已有项目使用自定义 lane 时,在对应 lane 中调用上面的 Action 即可。
|
|
264
|
+
|
|
265
|
+
#### 资源 JSON 参数
|
|
266
|
+
|
|
267
|
+
| JSON 参数 | 默认值 | 用途 |
|
|
268
|
+
| --- | --- | --- |
|
|
269
|
+
| `app_identifier` | `BUNDLE_ID` | 应用的 Bundle ID,最终不能为空 |
|
|
270
|
+
| `app_version` | 未设置 | 目标商店版本;选择构建或提交审核时必填 |
|
|
271
|
+
| `build_number` | 未设置 | 精确 Build 号;选择构建或提交审核时必填,使用字符串 |
|
|
272
|
+
| `metadata_path` / `screenshots_path` | `fastlane/metadata` / `fastlane/screenshots` | 相对路径以项目根目录为基准;未启用的资源类别不要求目录存在 |
|
|
273
|
+
| `metadata_changed` | `true` | 上传 metadata;设为 `false` 可跳过 |
|
|
274
|
+
| `screenshots_changed` | `false` | 上传截图,需显式开启 |
|
|
275
|
+
| `upload_metadata_on_new_version` | `true` | 指定 `app_version` 且目标可编辑版本不存在时补传 metadata,即使 `metadata_changed=false` |
|
|
276
|
+
| `download_missing_metadata` / `download_missing_screenshots` | `false` | 从 App Store Connect 初始化空的资源目录;不覆盖已有本地资源 |
|
|
277
|
+
| `use_live_version` | `false` | 初始化截图时使用线上版本 |
|
|
278
|
+
| `sync_screenshots` / `overwrite_screenshots` | `false` | 同步或替换远端截图,仅 `screenshots_changed=true` 时生效;同步还需 `FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS=true` |
|
|
279
|
+
| `select_build` | `false` | 按 `app_version` + `build_number` 选择处理完成的精确构建 |
|
|
280
|
+
| `wait_for_build_processing` | `true` | 选择构建前等待 Apple 处理 |
|
|
281
|
+
| `build_processing_timeout` / `build_processing_poll_interval` | `3600` / `30` | 等待超时和轮询间隔,单位秒 |
|
|
282
|
+
| `build_processing_retry_limit` / `build_processing_retry_interval` | `3` / `15` | 临时网络错误的重试次数和间隔,仍受总超时约束 |
|
|
283
|
+
| `submit_for_review` / `automatic_release` | `false` | 显式开启审核提交、审核通过后自动发布 |
|
|
284
|
+
| `release_notes` | 未设置 | 按语言提供更新说明的 JSON 对象,覆盖对应 `release_notes.txt` |
|
|
285
|
+
| `submission_information` | 未设置 | 提交审核所需的出口合规等信息 |
|
|
286
|
+
| `api_key_path` / `api_key` | 未设置 | API Key JSON 路径或 Key Hash,二者互斥 |
|
|
287
|
+
| `username` | 未设置 | 使用 Apple ID 登录时的用户名 |
|
|
288
|
+
| `platform` | `ios` | 当前资源 Action 仅支持 iOS |
|
|
289
|
+
| `force` | `true` | 跳过 deliver 的 HTML 预览确认 |
|
|
290
|
+
|
|
291
|
+
配置优先级为**显式 Action 参数 > JSON > 默认值**。`package` 会用本次实际的 Bundle ID、版本号和 Build 号覆盖 JSON,避免选择旧构建;独立调用需要自行填写目标版本和构建号。开启 `select_build` 或 `submit_for_review` 时,两者均为必填。传给 `package` / `upload_store` 的 `release_notes` 仍沿用原 JSON 字符串格式,仅在上传 metadata 时生效。
|
|
292
|
+
|
|
293
|
+
#### 常见使用场景
|
|
294
|
+
|
|
295
|
+
以下资源操作均以总开关已开启为前提。资源的变更开关由项目或 CI 设置,插件不自行运行 Git 差异检测。
|
|
296
|
+
|
|
297
|
+
| 场景 | 关键配置 |
|
|
298
|
+
| --- | --- |
|
|
299
|
+
| 只上传 IPA | 总开关关闭;不执行资源流程 |
|
|
300
|
+
| 只修改文案 | `metadata_changed=true`,`screenshots_changed=false`,调用独立资源 Action |
|
|
301
|
+
| 只更新截图 | `metadata_changed=false`,`screenshots_changed=true`,`upload_metadata_on_new_version=false` |
|
|
302
|
+
| 上传 IPA 后绑定本次构建 | 调用 `package`,资源 JSON 中配置 `select_build=true`;版本和 Build 使用本次产物值 |
|
|
303
|
+
| 仅选择已有构建 | 独立调用时提供 `app_version`、`build_number`,设置 `select_build=true`、两个 `*_changed=false`、`upload_metadata_on_new_version=false` |
|
|
304
|
+
| 提交审核 | 设置 `submit_for_review=true` 并提供版本与 Build;先确认构建处理成功并绑定,再提交审核 |
|
|
305
|
+
|
|
306
|
+
`select_build`、`submit_for_review`、`automatic_release` 均默认关闭。等待处理超时、构建处理失败或可编辑版本不匹配时会报错,不会改选其他构建。`automatic_release` 只控制本次审核通过后的发布方式,需配合 `submit_for_review=true` 使用。
|
|
307
|
+
|
|
308
|
+
首次只下载资源时,可以直接调用:
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
app_store_resources(
|
|
312
|
+
app_store_resources_enabled: true,
|
|
313
|
+
app_identifier: "com.example.app",
|
|
314
|
+
metadata_path: "fastlane/metadata",
|
|
315
|
+
screenshots_path: "fastlane/screenshots",
|
|
316
|
+
metadata_changed: false,
|
|
317
|
+
screenshots_changed: false,
|
|
318
|
+
upload_metadata_on_new_version: false,
|
|
319
|
+
download_missing_metadata: true,
|
|
320
|
+
download_missing_screenshots: true,
|
|
321
|
+
use_live_version: true,
|
|
322
|
+
select_build: false,
|
|
323
|
+
submit_for_review: false,
|
|
324
|
+
automatic_release: false
|
|
325
|
+
)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
此例的认证仍读取环境配置,截图使用已有线上版本;尚无线上版本时,需使用可编辑版本并设置 `use_live_version=false`。下载只初始化空的资源类别,不覆盖本地已有文案或截图。
|
|
329
|
+
|
|
330
|
+
#### 旧用法与失败处理
|
|
331
|
+
|
|
332
|
+
- 旧 lane 仅传 `release_notes` 时,现在只上传 IPA;要上传更新说明,必须开启总开关并提供资源配置,且允许上传 metadata。
|
|
333
|
+
- 总开关关闭时,资源路径和资源子开关不会生效,`Deliverfile` 中开启截图同步也不会绕过 IPA 上传阶段的禁用设置。
|
|
334
|
+
- `package` 开启资源功能但未配置路径时,会在构建前报错;`upload_store` 会在认证或上传前报错。
|
|
335
|
+
- 开启后的 JSON 格式错误、未知字段、无效参数类型或空资源目录会终止任务。若资源上传失败,后续构建选择和审核提交不会继续;已成功上传的 IPA 不会回滚。
|
|
336
|
+
- TestFlight、Zealot、Fir 和蒲公英不使用商店资源总开关。
|
|
337
|
+
|
|
338
|
+
仅查看参数说明、不会触发上传的命令:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
bundle exec fastlane action package
|
|
342
|
+
bundle exec fastlane action upload_store
|
|
343
|
+
bundle exec fastlane action app_store_resources
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
目录格式和字段遵循 [Fastlane deliver 文档](https://docs.fastlane.tools/actions/deliver/)。
|
|
347
|
+
|
|
348
|
+
### 7. Zealot(仅 iOS)
|
|
349
|
+
|
|
350
|
+
通过官方 [fastlane-plugin-zealot](https://github.com/tryzealot/fastlane-plugin-zealot) 封装以下独立 Action:
|
|
351
|
+
|
|
352
|
+
| Action | 用途 |
|
|
353
|
+
| --- | --- |
|
|
354
|
+
| `upload_zealot` | 上传 IPA,返回版本与下载地址 |
|
|
355
|
+
| `upload_zealot_dsym` | 上传 iOS dSYM,支持 zip 或 xcarchive |
|
|
356
|
+
| `check_zealot_version` | 按 Bundle ID、版本号或 commit 查询版本 |
|
|
357
|
+
| `sync_zealot_devices` | 将 Apple 开发者账号中的 iOS 设备同步到 Zealot |
|
|
358
|
+
|
|
359
|
+
在环境文件或 CI 环境变量中配置:
|
|
360
|
+
|
|
361
|
+
```dotenv
|
|
362
|
+
ZEALOT_ENDPOINT=https://zealot.example.com
|
|
363
|
+
ZEALOT_TOKEN=your-user-token
|
|
364
|
+
ZEALOT_CHANNEL_KEY=your-ios-channel-key
|
|
365
|
+
ZEALOT_UPLOAD_DSYM=false
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
`package` 与 Fir 一样按 token 判断是否上传:配置 `ZEALOT_TOKEN` 后,自动上传 `development`、`ad-hoc`、`enterprise` 包;token 留空时跳过。上传时必须同时提供 `ZEALOT_ENDPOINT` 和 `ZEALOT_CHANNEL_KEY`。`app-store` 和 `testFlight` 保持原上传流程。
|
|
369
|
+
|
|
370
|
+
```ruby
|
|
371
|
+
package(
|
|
372
|
+
export_method: "development",
|
|
373
|
+
is_upload_zealot_dsym: true, # 默认 false;仅 IPA 上传成功后执行
|
|
374
|
+
changelog: "iOS 更新说明"
|
|
375
|
+
)
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
也可以单独调用,不需要重新构建:
|
|
379
|
+
|
|
380
|
+
```ruby
|
|
381
|
+
result = upload_zealot(file: "./App.ipa", changelog: "iOS 更新说明")
|
|
382
|
+
# result:app_id、release_id、release_url、install_url、qrcode_url
|
|
383
|
+
|
|
384
|
+
upload_zealot_dsym(zip_file: "./App.app.dSYM.zip")
|
|
385
|
+
# 或指定 path: "./App.xcarchive";均未指定时使用本次 gym 产物。
|
|
386
|
+
|
|
387
|
+
exists = check_zealot_version(
|
|
388
|
+
bundle_id: "com.example.app",
|
|
389
|
+
release_version: "1.0",
|
|
390
|
+
build_version: "1"
|
|
391
|
+
)
|
|
392
|
+
# 也可用 git_commit 替代 release_version / build_version。
|
|
393
|
+
|
|
394
|
+
sync_zealot_devices(api_key_path: "./app_store_connect_api_key.json")
|
|
395
|
+
# 也可使用 username / team_id;设备同步不会在 package 中自动执行。
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
请求失败默认终止 lane,可传 `fail_on_error: false` 或设置 `ZEALOT_FAIL_ON_ERROR=false` 继续执行。版本查询返回 `true`(存在)、`false`(不存在)、`nil`(请求失败且允许继续);设备同步返回 `total`、`succeeded`、`failed`。token 在请求摘要中始终隐藏。
|
|
399
|
+
|
|
400
|
+
上传参数支持官方的 `password`、`timeout`、`verify_ssl`、`branch`、`git_commit` 等选项,使用 `bundle exec fastlane action upload_zealot` 查看。示例 Fastfile 也提供 `uploadZealot`、`uploadZealotDsym`、`checkZealotVersion`、`syncZealotDevices` 四个 lane。
|
|
401
|
+
|
|
402
|
+
依赖兼容:Zealot 的 `debug_file` 依赖 `ruby-macho < 3`,不能与 CocoaPods 1.17(依赖 4.x)放在同一 bundle。此类工程应将 CocoaPods 放入独立 Gemfile;使用 Faraday 1 的 Fastlane 工程还应将 `faraday-net_http` 限制为 `~> 1.0`。
|
|
403
|
+
|
|
404
|
+
## 发布到 RubyGems
|
|
405
|
+
|
|
406
|
+
工作流位于 [`.github/workflows/release.yml`](.github/workflows/release.yml)。使用 `1.0.0` 这样的纯版本标签,无需 `v` 前缀。推送数字开头的标签后,自动校验标签与 `lib/fastlane/plugin/fastci/version.rb` 中的 `VERSION` 完全一致,检查 Ruby 语法、构建 gem 并发布到 RubyGems。
|
|
407
|
+
|
|
408
|
+
首次使用需完成一次 [RubyGems Trusted Publishing 配置](https://guides.rubygems.org/trusted-publishing/):
|
|
409
|
+
|
|
410
|
+
用 gem 所有者账号打开 [fastlane-plugin-fastci](https://rubygems.org/gems/fastlane-plugin-fastci),进入 **Trusted publishers → Create**,填写:
|
|
411
|
+
|
|
412
|
+
| 字段 | 值 |
|
|
413
|
+
| --- | --- |
|
|
414
|
+
| Repository owner | `watermelon520` |
|
|
415
|
+
| Repository name | `fastlane-plugin-fastci` |
|
|
416
|
+
| Workflow filename | `release.yml` |
|
|
417
|
+
| Environment | 留空(可选) |
|
|
418
|
+
|
|
419
|
+
工作流使用官方 OIDC 短期凭据,不需要配置 `RUBYGEMS_API_KEY` 或创建 GitHub Environment。工作流文件在当前仓库内,Workflow Repository 两项留空。若以后设置 Environment,RubyGems 配置与工作流的 `environment` 必须保持一致。
|
|
420
|
+
|
|
421
|
+
每次发布先修改 `VERSION`,执行 `bundle install` 同步 `Gemfile.lock`,并提交本次拟发布的代码和工作流。然后推送对应标签,例如版本更新为 `0.0.40` 后:
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
git push origin main
|
|
425
|
+
git tag -a 0.0.40 -m "Release 0.0.40"
|
|
426
|
+
git push origin 0.0.40
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
到 GitHub **Actions → Release to RubyGems** 查看结果。已发布版本不能覆盖;失败重跑前先确认该版本是否已经发布。只有打入标签提交的文件会被发布,本地未提交改动不会包含在内。
|
|
430
|
+
|
|
127
431
|
## 贡献与支持
|
|
128
432
|
|
|
129
433
|
如需更多帮助或贡献,请提交 Issue 或 PR。
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require 'fastlane/plugin/fastci/helper/app_store_resources_helper'
|
|
3
|
+
include Fastlane::Helper
|
|
4
|
+
|
|
5
|
+
module Fastlane
|
|
6
|
+
module Actions
|
|
7
|
+
# 校验并上传 App Store Connect metadata 和截图
|
|
8
|
+
class AppStoreResourcesAction < Action
|
|
9
|
+
# 独立资源入口:准备资源 -> 上传 -> 可选构建选择 -> 可选提交审核,全程不上传 IPA。
|
|
10
|
+
def self.run(params)
|
|
11
|
+
return nil unless resources_enabled?(params)
|
|
12
|
+
|
|
13
|
+
params = prepare_resources(params)
|
|
14
|
+
upload_resources(params)
|
|
15
|
+
select_build_and_submit_review(params)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# 总开关先于配置读取和认证检查,单独指定路径或资源子开关不能启用此能力。
|
|
19
|
+
def self.resources_enabled?(params)
|
|
20
|
+
return true if params[:app_store_resources_enabled] == true
|
|
21
|
+
|
|
22
|
+
UI.message('*************| 商店资源功能未开启,跳过(APP_STORE_RESOURCES_ENABLED=false)|*************')
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# 统一读取配置、建立认证并准备资源目录,下载与校验规则由 Helper 负责。
|
|
27
|
+
def self.prepare_resources(params)
|
|
28
|
+
params = AppStoreResourcesHelper.load_params(params)
|
|
29
|
+
params.merge!(AppStoreResourcesHelper.authentication_options(params, other_action))
|
|
30
|
+
AppStoreResourcesHelper.prepare(params)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# 只上传配置指定的资源类别,无资源变化时跳过上传。
|
|
34
|
+
def self.upload_resources(params)
|
|
35
|
+
if params[:metadata_changed] || params[:screenshots_changed]
|
|
36
|
+
UI.message('*************| 开始上传 App Store Connect 资源 |*************')
|
|
37
|
+
other_action.upload_to_app_store(
|
|
38
|
+
AppStoreResourcesHelper.resource_options(params, params[:metadata_path], params[:screenshots_path])
|
|
39
|
+
)
|
|
40
|
+
UI.success('App Store Connect 资源上传完成')
|
|
41
|
+
else
|
|
42
|
+
UI.message('*************| 没有 metadata 或截图变更,跳过资源上传 |*************')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# 资源上传完成后,按配置选择精确构建并提交审核;两个步骤默认均不执行。
|
|
47
|
+
def self.select_build_and_submit_review(params)
|
|
48
|
+
# 提交审核也必须先确认精确构建,不能依赖 deliver 自动选择最新 Build。
|
|
49
|
+
if params[:select_build] || params[:submit_for_review]
|
|
50
|
+
AppStoreResourcesHelper.select_build(params)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if params[:submit_for_review]
|
|
54
|
+
UI.message('*************| 开始提交 App Store 审核 |*************')
|
|
55
|
+
other_action.upload_to_app_store(AppStoreResourcesHelper.review_options(params))
|
|
56
|
+
UI.success('App Store 审核提交完成')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private_class_method :resources_enabled?, :prepare_resources, :upload_resources, :select_build_and_submit_review
|
|
61
|
+
|
|
62
|
+
def self.description
|
|
63
|
+
'校验并上传 App Store Connect metadata 和截图'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# JSON 合并后也通过这组参数校验,使文件配置与直接调用拥有相同约束。
|
|
67
|
+
def self.available_options
|
|
68
|
+
[
|
|
69
|
+
FastlaneCore::ConfigItem.new(
|
|
70
|
+
key: :app_store_resources_enabled,
|
|
71
|
+
env_name: 'APP_STORE_RESOURCES_ENABLED',
|
|
72
|
+
description: '商店资源总开关,必须显式开启后才能使用资源上传、下载及发布流程',
|
|
73
|
+
optional: true,
|
|
74
|
+
default_value: false,
|
|
75
|
+
type: Boolean
|
|
76
|
+
),
|
|
77
|
+
FastlaneCore::ConfigItem.new(
|
|
78
|
+
key: :config_path,
|
|
79
|
+
env_name: 'APP_STORE_RESOURCES_CONFIG_PATH',
|
|
80
|
+
description: '资源发布 JSON 配置文件路径,显式参数优先于配置文件',
|
|
81
|
+
optional: true,
|
|
82
|
+
default_value: nil,
|
|
83
|
+
# 路径校验由开启后的 load_params 执行,关闭功能时不读取或校验资源文件。
|
|
84
|
+
type: String
|
|
85
|
+
),
|
|
86
|
+
FastlaneCore::ConfigItem.new(
|
|
87
|
+
key: :app_identifier,
|
|
88
|
+
description: 'App Store Connect App 的 Bundle ID',
|
|
89
|
+
optional: true,
|
|
90
|
+
type: String
|
|
91
|
+
),
|
|
92
|
+
FastlaneCore::ConfigItem.new(
|
|
93
|
+
key: :app_version,
|
|
94
|
+
description: '要更新的 App Store 版本号',
|
|
95
|
+
optional: true,
|
|
96
|
+
default_value: nil,
|
|
97
|
+
type: String
|
|
98
|
+
),
|
|
99
|
+
FastlaneCore::ConfigItem.new(
|
|
100
|
+
key: :metadata_path,
|
|
101
|
+
description: 'metadata 目录路径',
|
|
102
|
+
optional: true,
|
|
103
|
+
default_value: 'fastlane/metadata',
|
|
104
|
+
type: String
|
|
105
|
+
),
|
|
106
|
+
FastlaneCore::ConfigItem.new(
|
|
107
|
+
key: :screenshots_path,
|
|
108
|
+
description: '截图目录路径',
|
|
109
|
+
optional: true,
|
|
110
|
+
default_value: 'fastlane/screenshots',
|
|
111
|
+
type: String
|
|
112
|
+
),
|
|
113
|
+
FastlaneCore::ConfigItem.new(
|
|
114
|
+
key: :metadata_changed,
|
|
115
|
+
description: '是否上传 metadata',
|
|
116
|
+
optional: true,
|
|
117
|
+
default_value: true,
|
|
118
|
+
type: Boolean
|
|
119
|
+
),
|
|
120
|
+
FastlaneCore::ConfigItem.new(
|
|
121
|
+
key: :screenshots_changed,
|
|
122
|
+
description: '是否上传截图',
|
|
123
|
+
optional: true,
|
|
124
|
+
default_value: false,
|
|
125
|
+
type: Boolean
|
|
126
|
+
),
|
|
127
|
+
FastlaneCore::ConfigItem.new(
|
|
128
|
+
key: :upload_metadata_on_new_version,
|
|
129
|
+
description: '目标 App Store 版本不存在时是否强制上传 metadata',
|
|
130
|
+
optional: true,
|
|
131
|
+
default_value: true,
|
|
132
|
+
type: Boolean
|
|
133
|
+
),
|
|
134
|
+
FastlaneCore::ConfigItem.new(
|
|
135
|
+
key: :download_missing_metadata,
|
|
136
|
+
description: 'metadata 缺失时是否从 App Store Connect 下载',
|
|
137
|
+
optional: true,
|
|
138
|
+
default_value: false,
|
|
139
|
+
type: Boolean
|
|
140
|
+
),
|
|
141
|
+
FastlaneCore::ConfigItem.new(
|
|
142
|
+
key: :download_missing_screenshots,
|
|
143
|
+
description: '截图缺失时是否从 App Store Connect 下载',
|
|
144
|
+
optional: true,
|
|
145
|
+
default_value: false,
|
|
146
|
+
type: Boolean
|
|
147
|
+
),
|
|
148
|
+
FastlaneCore::ConfigItem.new(
|
|
149
|
+
key: :use_live_version,
|
|
150
|
+
description: '下载截图时是否使用线上版本',
|
|
151
|
+
optional: true,
|
|
152
|
+
default_value: false,
|
|
153
|
+
type: Boolean
|
|
154
|
+
),
|
|
155
|
+
FastlaneCore::ConfigItem.new(
|
|
156
|
+
key: :api_key,
|
|
157
|
+
description: 'App Store Connect API Key Hash',
|
|
158
|
+
optional: true,
|
|
159
|
+
sensitive: true,
|
|
160
|
+
type: Hash,
|
|
161
|
+
conflicting_options: [:api_key_path]
|
|
162
|
+
),
|
|
163
|
+
FastlaneCore::ConfigItem.new(
|
|
164
|
+
key: :api_key_path,
|
|
165
|
+
description: 'App Store Connect API Key JSON 文件路径',
|
|
166
|
+
optional: true,
|
|
167
|
+
type: String,
|
|
168
|
+
conflicting_options: [:api_key],
|
|
169
|
+
verify_block: proc do |value|
|
|
170
|
+
UI.user_error!("API Key JSON 不存在: #{value}") unless File.file?(value)
|
|
171
|
+
end
|
|
172
|
+
),
|
|
173
|
+
FastlaneCore::ConfigItem.new(
|
|
174
|
+
key: :username,
|
|
175
|
+
description: 'Apple ID 用户名,仅在未提供 API Key 时使用',
|
|
176
|
+
optional: true,
|
|
177
|
+
type: String
|
|
178
|
+
),
|
|
179
|
+
FastlaneCore::ConfigItem.new(
|
|
180
|
+
key: :platform,
|
|
181
|
+
description: 'App Store Connect 平台',
|
|
182
|
+
optional: true,
|
|
183
|
+
default_value: 'ios',
|
|
184
|
+
type: String,
|
|
185
|
+
verify_block: proc { |value| UI.user_error!('资源上传仅支持 ios 平台') unless value == 'ios' }
|
|
186
|
+
),
|
|
187
|
+
FastlaneCore::ConfigItem.new(
|
|
188
|
+
key: :sync_screenshots,
|
|
189
|
+
description: '是否让远端截图与本地截图同步',
|
|
190
|
+
optional: true,
|
|
191
|
+
default_value: false,
|
|
192
|
+
type: Boolean
|
|
193
|
+
),
|
|
194
|
+
FastlaneCore::ConfigItem.new(
|
|
195
|
+
key: :overwrite_screenshots,
|
|
196
|
+
description: '上传前是否清空远端截图',
|
|
197
|
+
optional: true,
|
|
198
|
+
default_value: false,
|
|
199
|
+
type: Boolean
|
|
200
|
+
),
|
|
201
|
+
FastlaneCore::ConfigItem.new(
|
|
202
|
+
key: :submit_for_review,
|
|
203
|
+
description: '上传资源后是否提交审核',
|
|
204
|
+
optional: true,
|
|
205
|
+
default_value: false,
|
|
206
|
+
type: Boolean
|
|
207
|
+
),
|
|
208
|
+
FastlaneCore::ConfigItem.new(
|
|
209
|
+
key: :automatic_release,
|
|
210
|
+
description: '审核通过后是否自动发布',
|
|
211
|
+
optional: true,
|
|
212
|
+
default_value: false,
|
|
213
|
+
type: Boolean
|
|
214
|
+
),
|
|
215
|
+
FastlaneCore::ConfigItem.new(
|
|
216
|
+
key: :select_build,
|
|
217
|
+
description: '是否按 app_version 和 build_number 自动选择构建',
|
|
218
|
+
optional: true,
|
|
219
|
+
default_value: false,
|
|
220
|
+
type: Boolean
|
|
221
|
+
),
|
|
222
|
+
FastlaneCore::ConfigItem.new(
|
|
223
|
+
key: :build_number,
|
|
224
|
+
description: '要选择的精确 Build Number',
|
|
225
|
+
optional: true,
|
|
226
|
+
default_value: nil,
|
|
227
|
+
type: String
|
|
228
|
+
),
|
|
229
|
+
FastlaneCore::ConfigItem.new(
|
|
230
|
+
key: :wait_for_build_processing,
|
|
231
|
+
description: '选择构建前是否等待 App Store Connect 处理完成',
|
|
232
|
+
optional: true,
|
|
233
|
+
default_value: true,
|
|
234
|
+
type: Boolean
|
|
235
|
+
),
|
|
236
|
+
FastlaneCore::ConfigItem.new(
|
|
237
|
+
key: :build_processing_timeout,
|
|
238
|
+
description: '等待构建处理完成的超时时间,单位秒',
|
|
239
|
+
optional: true,
|
|
240
|
+
default_value: 3600,
|
|
241
|
+
type: Integer,
|
|
242
|
+
verify_block: proc { |value| UI.user_error!('构建处理超时必须大于 0') unless value.positive? }
|
|
243
|
+
),
|
|
244
|
+
FastlaneCore::ConfigItem.new(
|
|
245
|
+
key: :build_processing_poll_interval,
|
|
246
|
+
description: '查询构建处理状态的时间间隔,单位秒',
|
|
247
|
+
optional: true,
|
|
248
|
+
default_value: 30,
|
|
249
|
+
type: Integer,
|
|
250
|
+
verify_block: proc { |value| UI.user_error!('构建轮询间隔必须大于 0') unless value.positive? }
|
|
251
|
+
),
|
|
252
|
+
FastlaneCore::ConfigItem.new(
|
|
253
|
+
key: :build_processing_retry_limit,
|
|
254
|
+
description: '查询构建处理状态遇到网络错误时的最大重试次数',
|
|
255
|
+
optional: true,
|
|
256
|
+
default_value: 3,
|
|
257
|
+
type: Integer,
|
|
258
|
+
verify_block: proc { |value| UI.user_error!('构建查询重试次数不能小于 0') if value.negative? }
|
|
259
|
+
),
|
|
260
|
+
FastlaneCore::ConfigItem.new(
|
|
261
|
+
key: :build_processing_retry_interval,
|
|
262
|
+
description: '查询构建处理状态网络错误后的重试等待时间,单位秒',
|
|
263
|
+
optional: true,
|
|
264
|
+
default_value: 15,
|
|
265
|
+
type: Integer,
|
|
266
|
+
verify_block: proc { |value| UI.user_error!('构建查询重试间隔不能小于 0') if value.negative? }
|
|
267
|
+
),
|
|
268
|
+
FastlaneCore::ConfigItem.new(
|
|
269
|
+
key: :submission_information,
|
|
270
|
+
description: 'deliver 提交审核信息,例如出口合规声明',
|
|
271
|
+
optional: true,
|
|
272
|
+
default_value: nil,
|
|
273
|
+
type: Hash
|
|
274
|
+
),
|
|
275
|
+
FastlaneCore::ConfigItem.new(
|
|
276
|
+
key: :release_notes,
|
|
277
|
+
description: '按语言配置的更新说明;优先于 metadata 中的 release_notes.txt',
|
|
278
|
+
optional: true,
|
|
279
|
+
type: Hash
|
|
280
|
+
),
|
|
281
|
+
FastlaneCore::ConfigItem.new(
|
|
282
|
+
key: :force,
|
|
283
|
+
description: '是否跳过 HTML 预览确认',
|
|
284
|
+
optional: true,
|
|
285
|
+
default_value: true,
|
|
286
|
+
type: Boolean
|
|
287
|
+
)
|
|
288
|
+
]
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def self.is_supported?(platform)
|
|
292
|
+
platform == :ios
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def self.category
|
|
296
|
+
:production
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|