pindo 5.12.1 → 5.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 298ff00b838b7929bf82b9d0f1751afa68a7aa09cb00b3aa64991b807cb101f8
4
- data.tar.gz: 21ae02b4b9edc916262eb1a72ed417e7fd875454a6870af99bfb699d404f7783
3
+ metadata.gz: ce0a5c40dcd8dbdcef15ad36aebc63fa189108aa38e05923e81662830a4a2996
4
+ data.tar.gz: c05cd7079948fa242597eceaccb3cab522035fad0a63b53a3e9a0af6296309f9
5
5
  SHA512:
6
- metadata.gz: ccc097a2e5400394bcdcb3dfffc44bb366ff590163af4643d6e5be910884127e15c589c94b5fe408844c7de4eeff4a9e3830c0303f1399e2a82076484122e5a9
7
- data.tar.gz: 342289896b13603e77226b8d6ef18a8c1549b8fe265050ba3f9e869b3c3f7e327f5623aa300b0dbdef526a39f839977cb55837d2fa209ab48e214937b7738e98
6
+ metadata.gz: f7f88c219338108d5107f7b3436763a93186e91bebc5b27d608f9ae1f2e7d01185ea0727aa1162357ae07fd8aae682d883b3c57a676e328d096b04ce7bebbb08
7
+ data.tar.gz: 22cc175b1716238b98613116c9103d4b2324e3e3394f2f965a8d76c99144e3c197793ccdfefa733aea0d3e516340582b938a3b3ea533e150baa9a18d3406049a
@@ -646,6 +646,22 @@ module Pindo
646
646
  new_tag
647
647
  end
648
648
 
649
+ # 检查仓库是否有未提交的更改(包括未暂存和已暂存的更改)
650
+ # @param git_root_dir [String] 项目目录路径
651
+ # @return [Boolean] 如果有未提交的更改返回true,否则返回false
652
+ def has_uncommitted_changes?(git_root_dir:nil)
653
+ return false if git_root_dir.nil?
654
+
655
+ begin
656
+ # 使用 git status --porcelain 检查是否有更改
657
+ # 如果输出不为空,说明有未提交的更改
658
+ status_output = git!(%W(-C #{git_root_dir} status --porcelain)).strip
659
+ !status_output.empty?
660
+ rescue StandardError => e
661
+ false
662
+ end
663
+ end
664
+
649
665
  # 检查tag是否在指定的commit上
650
666
  # @param git_root_dir [String] 项目目录路径
651
667
  # @param tag_name [String] 标签名称
@@ -109,13 +109,19 @@ module Pindo
109
109
  # 初始化三级结构(总是保存到内存,不管是否启用缓存)
110
110
  @memory_selections[project_path] ||= {}
111
111
  @memory_selections[project_path][root_command] ||= {}
112
- @memory_selections[project_path][root_command][key] = value
112
+
113
+ # 如果值为 nil,则删除该键而不是保存 nil
114
+ if value.nil?
115
+ @memory_selections[project_path][root_command].delete(key)
116
+ puts "[PindoContext] 从内存删除: [#{project_path}][#{root_command}][#{key}]" if verbose?
117
+ else
118
+ @memory_selections[project_path][root_command][key] = value
119
+ puts "[PindoContext] 保存到内存: [#{project_path}][#{root_command}][#{key}] = #{value.inspect}" if verbose?
120
+ end
113
121
 
114
122
  # 更新该命令组的最后修改时间
115
123
  @memory_selections[project_path][root_command]['__last_modified__'] = Time.now.to_i
116
124
 
117
- puts "[PindoContext] 保存到内存: [#{project_path}][#{root_command}][#{key}] = #{value.inspect}" if verbose?
118
-
119
125
  # 仅在启用缓存时保存到文件
120
126
  if @cache_enabled
121
127
  save_file_cache
@@ -306,6 +312,8 @@ module Pindo
306
312
  commands.each do |command, selections|
307
313
  file_cache[project_path][command] ||= {}
308
314
  selections.each do |key, value|
315
+ # 跳过 nil 值,不保存到文件
316
+ next if value.nil?
309
317
  # 将符号键转换为字符串
310
318
  string_key = key.to_s
311
319
  file_cache[project_path][command][string_key] = value
@@ -503,8 +511,9 @@ module Pindo
503
511
  puts "────────────────────────────────────────"
504
512
 
505
513
  cached_selections.each do |key, value|
506
- # 跳过内部字段
514
+ # 跳过内部字段和 nil 值
507
515
  next if key.to_s.start_with?('__')
516
+ next if value.nil?
508
517
 
509
518
  case key.to_s
510
519
  when 'bundle_id'
@@ -142,13 +142,9 @@ module Pindo
142
142
 
143
143
  tasks = []
144
144
 
145
- # 1. Git 标签任务(如果需要上传)
146
- if @args_upload_flag
147
- git_tag_task = Pindo::TaskSystem::GitTagTask.new(
148
- config[:project_path]
149
- )
150
- tasks << git_tag_task
151
- end
145
+ # 1. Git 标签任务(所有编译场景都需要打 Tag)
146
+ git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
147
+ tasks << git_tag_task
152
148
 
153
149
  # 2. Unity 导出任务(仅 Unity 工程)
154
150
  if is_unity
@@ -166,7 +162,7 @@ module Pindo
166
162
  export_path: android_export_path,
167
163
  context: unity_context
168
164
  )
169
- unity_task.dependencies << tasks.first.id if tasks.any?
165
+ unity_task.dependencies << git_tag_task.id
170
166
  tasks << unity_task
171
167
  end
172
168
 
@@ -1,7 +1,6 @@
1
1
 
2
2
  require 'pindo/command/android/autobuild'
3
3
  require 'pindo/command/android/autoresign'
4
- require 'pindo/command/android/build'
5
4
  require 'pindo/command/android/keystore'
6
5
 
7
6
 
@@ -104,7 +104,7 @@ module Pindo
104
104
  when :android
105
105
  puts "Android工程, 请使用 pindo and autobuild"
106
106
  when :unity
107
- raise Informative, "Unity工程, 请使用 pindo unity ipa 或者pindo unity apk"
107
+ raise Informative, "Unity工程, 请使用 pindo unity autobuild --types=ipa,apk"
108
108
  else
109
109
  raise Informative, "当前目录不是工程目录,不能编译"
110
110
  end
@@ -82,7 +82,7 @@ module Pindo
82
82
  puts "Android 工程, 请使用 pindo and build"
83
83
  Pindo::Command::Android::Build::run(args_temp)
84
84
  when :unity
85
- raise Informative, "Unity 工程, 请使用 pindo unity ipa 或者pindo unity apk"
85
+ raise Informative, "Unity 工程, 请使用 pindo unity autobuild --types=ipa,apk"
86
86
  else
87
87
  raise Informative, "当前目录不是工程目录,不能编译"
88
88
  end
@@ -140,11 +140,9 @@ module Pindo
140
140
 
141
141
  tasks = []
142
142
 
143
- # 1. Git 标签任务(如果需要上传)
144
- if @args_upload_flag
145
- git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
146
- tasks << git_tag_task
147
- end
143
+ # 1. Git 标签任务(所有编译场景都需要打 Tag)
144
+ git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
145
+ tasks << git_tag_task
148
146
 
149
147
  # 2. Unity 导出任务(仅 Unity 工程)
150
148
  if is_unity
@@ -162,7 +160,7 @@ module Pindo
162
160
  export_path: ios_export_path,
163
161
  context: unity_context
164
162
  )
165
- unity_task.dependencies << tasks.first.id if tasks.any?
163
+ unity_task.dependencies << git_tag_task.id
166
164
  tasks << unity_task
167
165
  end
168
166
 
@@ -91,7 +91,7 @@ module Pindo
91
91
  when :android
92
92
  raise Informative, "Android 工程, 请使用 pindo and build"
93
93
  when :unity
94
- raise Informative, "Unity 工程, 请使用 pindo unity ipa"
94
+ raise Informative, "Unity 工程, 请使用 pindo unity autobuild --types=ipa"
95
95
  else
96
96
  raise Informative, "当前目录不是工程目录,不能编译"
97
97
  end
@@ -7,6 +7,7 @@ require 'pindo/module/build/git_repo_helper'
7
7
  require 'pindo/module/build/build_helper'
8
8
  require 'pindo/module/task/task_manager'
9
9
  require 'pindo/module/task/model/upload_task'
10
+ require 'pindo/module/task/model/git_tag_task'
10
11
 
11
12
  module Pindo
12
13
  class Command
@@ -141,21 +142,15 @@ module Pindo
141
142
  tasks = []
142
143
 
143
144
  # 1. Git Tag 任务(检查并添加标签)
144
- git_repo_helper = Pindo::GitRepoHelper.share_instance
145
- Dir.chdir(project_dir)
146
- is_need_add_tag, tag_action_parms = git_repo_helper.check_is_need_add_tag?(project_dir)
147
- if is_need_add_tag
148
- git_repo_helper.create_and_push_tag(
149
- project_dir: project_dir,
150
- mode: 'minor',
151
- force_retag: tag_action_parms&.include?('--retag') || false,
152
- custom_tag: nil,
153
- release_branch: 'master'
154
- )
155
- end
145
+ git_tag_task = Pindo::TaskSystem::GitTagTask.new(project_dir)
146
+ tasks << git_tag_task
156
147
 
157
148
  # 2. 查找并创建上传任务
158
149
  upload_tasks = find_and_create_upload_tasks(project_dir)
150
+ # 让所有上传任务依赖 Git Tag 任务
151
+ upload_tasks.each do |upload_task|
152
+ upload_task.dependencies << git_tag_task.id
153
+ end
159
154
  tasks.concat(upload_tasks)
160
155
 
161
156
  tasks
@@ -11,6 +11,7 @@ require 'pindo/module/task/task_manager'
11
11
  require 'pindo/module/task/model/build_task'
12
12
  require 'pindo/module/task/model/unity_export_task'
13
13
  require 'pindo/module/task/model/upload_task'
14
+ require 'pindo/module/task/model/git_tag_task'
14
15
 
15
16
  module Pindo
16
17
  class Command
@@ -56,7 +57,7 @@ module Pindo
56
57
  $ pindo unity autobuild --upload # 编译所有类型并上传到JPS
57
58
 
58
59
  $ pindo unity autobuild --proj="My App" # 指定项目名称
59
- DESC
60
+ DESC
60
61
 
61
62
  # 命令参数
62
63
  self.arguments = [
@@ -139,27 +140,13 @@ DESC
139
140
  raise Informative, "当前目录不是Unity工程,请在Unity工程根目录下执行此命令"
140
141
  end
141
142
 
142
- if @args_upload_flag
143
- git_repo_helper = Pindo::GitRepoHelper.share_instance
144
- is_need_add_tag, tag_action_parms = git_repo_helper.check_is_need_add_tag?(pindo_project_dir)
145
- if is_need_add_tag
146
- git_repo_helper.create_and_push_tag(
147
- project_dir: pindo_project_dir,
148
- mode: 'minor',
149
- force_retag: tag_action_parms&.include?('--retag') || false,
150
- custom_tag: nil,
151
- release_branch: 'master'
152
- )
153
- end
154
- end
155
-
156
143
  # 1. 获取要构建的类型列表
157
144
  selected_platforms = get_selected_build_types()
158
145
 
159
146
  # 2. 按平台顺序准备所有配置(iOS → Android → Web)
160
147
  all_platform_configs = prepare_all_platform_configs(selected_platforms)
161
148
 
162
- # 3. 按平台顺序创建所有任务
149
+ # 3. 按平台顺序创建所有任务(包含 GitTagTask)
163
150
  all_tasks = make_task_with_config(selected_platforms, all_platform_configs)
164
151
 
165
152
  # 4. 统一添加到任务管理器并执行
@@ -178,38 +165,33 @@ DESC
178
165
  # 按平台顺序创建所有任务
179
166
  def make_task_with_config(selected_platforms, all_platform_configs)
180
167
  all_tasks = []
181
- build_tasks = [] # 收集所有构建任务
168
+ platform_build_tasks = {} # 存储平台对应的构建任务
169
+
170
+ # 第零步:创建 Git 标签任务(所有编译场景都需要打 Tag)
171
+ git_tag_task = Pindo::TaskSystem::GitTagTask.new(Dir.pwd)
172
+ all_tasks << git_tag_task
182
173
 
183
- # 第一步:创建所有导出和构建任务
174
+ # 第一步:为每个平台创建导出和构建任务
184
175
  selected_platforms.each do |platform|
185
176
  platform_config = all_platform_configs[platform]
186
177
 
187
- # 1. 创建 Unity 导出任务
178
+ # 1. 创建 Unity 导出任务(依赖 Git 标签任务)
188
179
  unity_task = create_unity_export_task(platform, all_platform_configs)
180
+ unity_task.dependencies << git_tag_task.id
189
181
  all_tasks << unity_task
190
182
 
191
- # 2. 创建构建任务
183
+ # 2. 创建构建任务(依赖导出任务)
192
184
  build_task = create_build_task(platform, platform_config, all_platform_configs, unity_task)
193
185
  all_tasks << build_task
194
- build_tasks << build_task # 收集构建任务
186
+ platform_build_tasks[platform] = build_task
195
187
  end
196
188
 
197
- # 第二步:创建所有上传任务(如果需要)
189
+ # 第二步:创建所有上传任务(最后添加,只依赖对应平台的构建任务)
190
+ # 注意:create_upload_task 内部已设置 dependencies: [build_task.id]
198
191
  if @args_upload_flag
199
- selected_platforms.each_with_index do |platform, index|
200
- # 获取对应平台的构建任务
201
- platform_build_task = build_tasks[index]
202
-
203
- # 创建上传任务
204
- upload_task = create_upload_task(platform, all_platform_configs, platform_build_task)
205
-
206
- # 让上传任务依赖所有构建任务完成
207
- build_tasks.each do |build_task|
208
- unless upload_task.dependencies.include?(build_task.id)
209
- upload_task.dependencies << build_task.id
210
- end
211
- end
212
-
192
+ selected_platforms.each do |platform|
193
+ build_task = platform_build_tasks[platform]
194
+ upload_task = create_upload_task(platform, all_platform_configs, build_task)
213
195
  all_tasks << upload_task
214
196
  end
215
197
  end
@@ -97,6 +97,9 @@ module Pindo
97
97
  puts "⚠ Keystore 签名配置跳过(使用工程原有配置)"
98
98
  end
99
99
 
100
+ # 处理 Play Asset Delivery 配置(如果存在)
101
+ setup_play_asset_delivery(project_dir)
102
+
100
103
  # 构建 APK
101
104
  build_apk(project_dir, debug)
102
105
  end
@@ -298,6 +301,113 @@ module Pindo
298
301
  end
299
302
  end
300
303
 
304
+ # 设置 Play Asset Delivery:直接扫描导出工程中的资源目录,按照 Android 原生方式创建 .androidpack 目录
305
+ def setup_play_asset_delivery(project_dir)
306
+ # 获取 unityLibrary 路径
307
+ unity_library_path = File.join(project_dir, "unityLibrary", "src", "main")
308
+ unless File.directory?(unity_library_path)
309
+ puts "警告:Unity Library 目录不存在: #{unity_library_path}"
310
+ return
311
+ end
312
+
313
+ # 扫描 assets 目录下的资源(Unity 构建时会将 StreamingAssets 复制到这里)
314
+ assets_path = File.join(unity_library_path, "assets")
315
+ unless File.directory?(assets_path)
316
+ puts "未找到 assets 目录,跳过 Play Asset Delivery 设置"
317
+ return
318
+ end
319
+
320
+ # 扫描 assets 目录下的所有一级子目录
321
+ # 这些目录对应 StreamingAssets/{DefaultYooFolderName} 下的资源包
322
+ asset_subdirs = Dir.glob(File.join(assets_path, "*")).select { |path| File.directory?(path) }
323
+
324
+ if asset_subdirs.empty?
325
+ puts "未找到 assets 下的子目录,跳过 Play Asset Delivery 设置"
326
+ return
327
+ end
328
+
329
+ puts "检测到 #{asset_subdirs.length} 个 assets 子目录,开始设置 Play Asset Delivery..."
330
+
331
+ begin
332
+ # 收集所有创建的 asset pack 模块名
333
+ created_pack_modules = []
334
+
335
+ # 扫描每个子目录,为每个子目录创建一个 asset pack 模块
336
+ asset_subdirs.each do |subdir|
337
+ original_pack_name = File.basename(subdir)
338
+ if original_pack_name.downcase == 'bin'
339
+ puts "跳过 bin 目录,保持在 base 模块中"
340
+ next
341
+ end
342
+ sanitized_pack_name = sanitize_pack_name(original_pack_name)
343
+ module_name = "#{sanitized_pack_name}_pack"
344
+
345
+ # 检查目录是否为空
346
+ if Dir.glob(File.join(subdir, "*")).empty?
347
+ puts "警告:跳过空的 Asset Pack 目录: #{subdir}"
348
+ next
349
+ end
350
+
351
+ # 创建模块目录(在项目顶级目录,与 launcher、unityLibrary 同级)
352
+ android_pack_dir = File.join(project_dir, module_name)
353
+ FileUtils.rm_rf(android_pack_dir) if File.directory?(android_pack_dir)
354
+ FileUtils.mkdir_p(android_pack_dir)
355
+
356
+ # 在 asset pack 模块中创建 src/main/assets 目录
357
+ module_assets_dir = File.join(android_pack_dir, "src", "main", "assets")
358
+ FileUtils.mkdir_p(module_assets_dir)
359
+
360
+ # 复制整个子目录到模块的 assets 下,保留原始目录名
361
+ FileUtils.cp_r(subdir, module_assets_dir)
362
+
363
+ # 从 assets 目录中删除资源,避免被打包到 base 模块
364
+ puts " 从 assets 目录移除资源 #{subdir},避免重复打包到 base 模块..."
365
+ FileUtils.rm_rf(subdir)
366
+
367
+ # 创建 build.gradle 文件(默认使用 install-time delivery mode)
368
+ build_gradle_content = <<~GRADLE
369
+ plugins {
370
+ id 'com.android.asset-pack'
371
+ }
372
+
373
+ assetPack {
374
+ packName = "#{module_name}"
375
+ dynamicDelivery {
376
+ deliveryType = "install-time"
377
+ }
378
+ }
379
+ GRADLE
380
+
381
+ build_gradle_path = File.join(android_pack_dir, "build.gradle")
382
+ File.write(build_gradle_path, build_gradle_content)
383
+
384
+ # 记录模块名(项目顶级目录下的简单模块名)
385
+ created_pack_modules << ":#{module_name}"
386
+
387
+ puts "✓ 已创建 Asset Pack: #{module_name} -> #{android_pack_dir}"
388
+ end
389
+
390
+ # 更新 settings.gradle 文件,注册 asset pack 模块
391
+ if created_pack_modules.any?
392
+ GradleHelper.update_settings_gradle(project_dir, created_pack_modules)
393
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
394
+ GradleHelper.update_launcher_build_gradle(project_dir, created_pack_modules)
395
+ puts "✓ Play Asset Delivery 设置完成,共创建 #{created_pack_modules.length} 个 Asset Pack"
396
+ else
397
+ puts "未找到有效的 Asset Pack 目录"
398
+ end
399
+ rescue => e
400
+ puts "警告:设置 Play Asset Delivery 失败: #{e.message}"
401
+ puts e.backtrace.first(5).join("\n")
402
+ end
403
+ end
404
+
405
+ def sanitize_pack_name(name)
406
+ sanitized = name.to_s.gsub(/[^A-Za-z0-9_]/, '_')
407
+ sanitized = "p_#{sanitized}" unless sanitized.match?(/^[A-Za-z]/)
408
+ sanitized = sanitized.gsub(/__+/, '_')
409
+ sanitized.empty? ? "pack" : sanitized
410
+ end
301
411
 
302
412
  end
303
413
  end
@@ -559,7 +559,95 @@ module Pindo
559
559
  end
560
560
  rescue => e
561
561
  false
562
+ end
563
+
564
+ end
565
+
566
+ # =================== Play Asset Delivery 相关方法 ===================
567
+
568
+ # 更新 settings.gradle 文件,注册 asset pack 模块
569
+ def self.update_settings_gradle(project_dir, pack_modules)
570
+ settings_gradle_path = File.join(project_dir, "settings.gradle")
571
+ settings_gradle_kts_path = File.join(project_dir, "settings.gradle.kts")
572
+
573
+ # 优先使用 settings.gradle.kts,否则使用 settings.gradle
574
+ settings_file = File.exist?(settings_gradle_kts_path) ? settings_gradle_kts_path : settings_gradle_path
575
+
576
+ unless File.exist?(settings_file)
577
+ puts "警告:未找到 settings.gradle 或 settings.gradle.kts 文件"
578
+ return
579
+ end
580
+
581
+ content = File.read(settings_file)
582
+ original_content = content.dup
583
+
584
+ # 模块名已经是正确的格式(如 :FGUI.androidpack)
585
+ pack_module_names = pack_modules
586
+
587
+ # 移除已存在的 asset pack 模块引用(避免重复)
588
+ pack_module_names.each do |module_name|
589
+ # 移除可能存在的旧引用
590
+ content.gsub!(/^\s*include\s+['"]#{Regexp.escape(module_name)}['"]\s*$/, '')
591
+ content.gsub!(/,\s*['"]#{Regexp.escape(module_name)}['"]/, '')
592
+ end
593
+
594
+ # 查找 include 语句的位置
595
+ include_pattern = /include\s+(['"]:launcher['"],\s*['"]:unityLibrary['"])/
596
+ if content.match(include_pattern)
597
+ # 在现有的 include 语句中添加 asset pack 模块
598
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
599
+ content.gsub!(include_pattern, "include \\1, #{pack_includes}")
600
+ else
601
+ # 如果没有找到标准格式,尝试在文件末尾添加
602
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
603
+ content += "\ninclude #{pack_includes}\n" unless content.include?(pack_includes)
604
+ end
605
+
606
+ # 只有当内容发生变化时才写入
607
+ if content != original_content
608
+ File.write(settings_file, content)
609
+ puts "✓ 已更新 #{File.basename(settings_file)},注册 #{pack_modules.length} 个 Asset Pack 模块"
610
+ puts " 模块: #{pack_module_names.join(', ')}"
611
+ else
612
+ puts "✓ #{File.basename(settings_file)} 已包含 Asset Pack 模块引用"
613
+ end
614
+ end
615
+
616
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
617
+ def self.update_launcher_build_gradle(project_dir, pack_modules)
618
+ launcher_build_gradle_path = File.join(project_dir, "launcher", "build.gradle")
619
+ unless File.exist?(launcher_build_gradle_path)
620
+ puts "警告:未找到 launcher/build.gradle 文件"
621
+ return
622
+ end
623
+
624
+ content = File.read(launcher_build_gradle_path)
625
+ original_content = content.dup
626
+
627
+ # 检查是否已有 assetPacks 配置
628
+ if content.match(/assetPacks\s*=\s*\[/)
629
+ # 更新现有的 assetPacks 配置
630
+ content.gsub!(/assetPacks\s*=\s*\[[^\]]*\]/, "assetPacks = #{pack_modules.inspect}")
631
+ else
632
+ # 在 android 块中添加 assetPacks 配置
633
+ android_block_pattern = /(android\s*\{)/
634
+ if content.match(android_block_pattern)
635
+ # 在 android { 后添加 assetPacks 配置
636
+ content.gsub!(android_block_pattern, "\\1\n assetPacks = #{pack_modules.inspect}")
637
+ else
638
+ puts "警告:未找到 android 块,无法添加 assetPacks 配置"
639
+ return
562
640
  end
563
641
  end
642
+
643
+ # 只有当内容发生变化时才写入
644
+ if content != original_content
645
+ File.write(launcher_build_gradle_path, content)
646
+ puts "✓ 已更新 launcher/build.gradle,添加 assetPacks 配置"
647
+ else
648
+ puts "✓ launcher/build.gradle 已包含 assetPacks 配置"
649
+ end
650
+ end
651
+
564
652
  end
565
653
  end
@@ -28,15 +28,13 @@ module Pindo
28
28
 
29
29
  # 1. 验证 Git 仓库
30
30
  unless is_git_directory?(local_repo_dir: project_dir)
31
- Funlog.instance.fancyinfo_error("当前目录不是git仓库,请在git仓库目录下执行此命令")
32
- return
31
+ raise Informative, "当前目录不是git仓库,请在git仓库目录下执行此命令"
33
32
  end
34
33
 
35
34
  # 获取git仓库根目录
36
35
  root_dir = git_root_directory(local_repo_dir: project_dir)
37
36
  if root_dir.nil?
38
- Funlog.instance.fancyinfo_error("无法获取git仓库根目录")
39
- return
37
+ raise Informative, "无法获取git仓库根目录"
40
38
  end
41
39
 
42
40
  # 2. 处理未提交的文件
@@ -54,13 +52,15 @@ module Pindo
54
52
  coding_branch: coding_branch
55
53
  )
56
54
 
57
- # 5. 添加版本标签
58
- add_release_tag(
55
+ # 5. 添加版本标签并返回 tag 名称
56
+ new_tag = add_release_tag(
59
57
  project_dir: root_dir,
60
58
  increment_mode: mode,
61
59
  force_retag: force_retag,
62
60
  custom_tag: custom_tag
63
61
  )
62
+
63
+ new_tag
64
64
  end
65
65
 
66
66
  # 检查并安装 git-cliff
@@ -192,7 +192,17 @@ module Pindo
192
192
  current_git_root_path = git_root_directory(local_repo_dir: project_path)
193
193
  latest_tag = get_latest_version_tag(project_dir: current_git_root_path)
194
194
 
195
- unless is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
195
+ # 检查是否需要打 tag:
196
+ # 1. 最新 tag 不在 HEAD 上,或者
197
+ # 2. 仓库有未提交的更改
198
+ tag_not_at_head = !is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
199
+ has_uncommitted = has_uncommitted_changes?(git_root_dir: current_git_root_path)
200
+
201
+ if tag_not_at_head || has_uncommitted
202
+ # 提示用户需要打 tag 的原因
203
+ if has_uncommitted && !tag_not_at_head
204
+ puts "\n注意:仓库有未提交的更改,建议提交后再打 Tag"
205
+ end
196
206
  # 检查环境变量
197
207
  env_tag_decision = ENV['PINDO_TAG_DECISION']
198
208
  if env_tag_decision && !env_tag_decision.empty?
@@ -340,9 +350,8 @@ module Pindo
340
350
  # 清除临时缓存
341
351
  self.temp_tag_decision = nil
342
352
  else
343
- # 清空持久化缓存
344
- context.set_selection(PindoContext::SelectionKey::TAG_DECISION, nil)
345
- # 保存到临时缓存(仅在内存中,不会写入文件)
353
+ # 不清空持久化缓存(避免将 nil 写入文件)
354
+ # 只使用临时缓存(仅在内存中,不会写入文件)
346
355
  self.temp_tag_decision = {
347
356
  action: selected_action,
348
357
  description: selected_description,
@@ -385,7 +394,7 @@ module Pindo
385
394
  else
386
395
  Funlog.instance.fancyinfo_success("tag #{new_tag} 已存在")
387
396
  Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
388
- return
397
+ return new_tag # 返回已存在的 tag
389
398
  end
390
399
  end
391
400
 
@@ -395,7 +404,7 @@ module Pindo
395
404
 
396
405
  Funlog.instance.fancyinfo_success("创建tag: #{new_tag}")
397
406
  Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
398
- return
407
+ return new_tag # 返回新创建的 tag
399
408
  end
400
409
 
401
410
  # 原有的自动递增逻辑
@@ -410,13 +419,13 @@ module Pindo
410
419
  )
411
420
  Funlog.instance.fancyinfo_success("创建初始tag: #{new_tag}")
412
421
  Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
413
- return
422
+ return new_tag # 返回初始 tag
414
423
  end
415
424
 
416
425
  if is_tag_at_head?(git_root_dir: project_dir, tag_name: latest_tag)
417
426
  Funlog.instance.fancyinfo_success("当前commit已有tag: #{latest_tag},无需重新打tag")
418
427
  Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
419
- return
428
+ return latest_tag # 返回已存在的 tag
420
429
  end
421
430
 
422
431
  Funlog.instance.fancyinfo_success("最近的上次tag是: #{latest_tag} ")
@@ -429,6 +438,8 @@ module Pindo
429
438
 
430
439
  Funlog.instance.fancyinfo_success("当前仓库的tag: #{new_tag}")
431
440
  Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
441
+
442
+ new_tag # 返回新创建的 tag
432
443
  end
433
444
 
434
445
  # 合并到发布分支
@@ -18,7 +18,7 @@ module Pindo
18
18
  end
19
19
 
20
20
  def self.default_retry_count
21
- 2 # 可以重试 2
21
+ 0 # 可以重试 0
22
22
  end
23
23
 
24
24
  def self.default_retry_delay
@@ -36,7 +36,7 @@ module Pindo
36
36
  attr_accessor :context, :metadata
37
37
  attr_reader :created_at, :started_at, :finished_at
38
38
  attr_accessor :retry_count # 剩余重试次数
39
- attr_reader :retry_mode, :retry_delay
39
+ attr_reader :retry_mode, :retry_delay, :max_retry_count # max_retry_count: 初始最大重试次数
40
40
  attr_accessor :callbacks_setup # 标记回调是否已经设置
41
41
 
42
42
  def initialize(name, options = {})
@@ -64,6 +64,7 @@ module Pindo
64
64
  # 重试配置
65
65
  @retry_mode = options[:retry_mode] || self.class.default_retry_mode
66
66
  @retry_count = options[:retry_count] || self.class.default_retry_count
67
+ @max_retry_count = @retry_count # 保存初始最大重试次数
67
68
  @retry_delay = options[:retry_delay] || self.class.default_retry_delay
68
69
  end
69
70
 
@@ -220,10 +221,16 @@ module Pindo
220
221
  end
221
222
  end
222
223
 
224
+ # 计算当前重试次数
225
+ def current_retry_attempt
226
+ @max_retry_count - @retry_count + 1
227
+ end
228
+
223
229
  # 立即重试
224
230
  def handle_immediate_retry
225
- puts "⚠️ 任务失败,立即重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
226
- puts " 错误: #{@error.message}"
231
+ attempt = current_retry_attempt
232
+ Funlog.warning("任务 [#{@name}] 失败,立即重试 (第#{attempt}次/共#{@max_retry_count}次)")
233
+ Funlog.warning(" 错误: #{@error.message}")
227
234
 
228
235
  before_retry
229
236
  reset_for_retry
@@ -232,9 +239,10 @@ module Pindo
232
239
 
233
240
  # 延迟重试
234
241
  def handle_delayed_retry
235
- puts "⚠️ 任务失败,延迟重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
236
- puts " 错误: #{@error.message}"
237
- puts " 延迟: #{@retry_delay}"
242
+ attempt = current_retry_attempt
243
+ Funlog.warning("任务 [#{@name}] 失败,延迟重试 (第#{attempt}次/共#{@max_retry_count}次)")
244
+ Funlog.warning(" 错误: #{@error.message}")
245
+ Funlog.warning(" 延迟: #{@retry_delay}秒")
238
246
 
239
247
  before_retry
240
248
  sleep(@retry_delay) if @retry_delay > 0
@@ -245,8 +253,9 @@ module Pindo
245
253
 
246
254
  # 下个任务重试
247
255
  def handle_next_task_retry
248
- puts "⚠️ 任务失败,下个任务重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
249
- puts " 错误: #{@error.message}"
256
+ attempt = current_retry_attempt
257
+ Funlog.warning("任务 [#{@name}] 失败,下个任务重试 (第#{attempt}次/共#{@max_retry_count}次)")
258
+ Funlog.warning(" 错误: #{@error.message}")
250
259
 
251
260
  before_retry
252
261
  @status = TaskStatus::FAILED
@@ -258,8 +267,8 @@ module Pindo
258
267
  def finalize_failure
259
268
  @status = TaskStatus::FAILED
260
269
 
261
- puts "[Task] #{@name} 最终失败".red if defined?(String.red)
262
- puts " 错误: #{@error.message}".red if defined?(String.red)
270
+ Funlog.instance.fancyinfo_error("[Task] #{@name} 最终失败")
271
+ Funlog.instance.fancyinfo_error(" 错误: #{@error.message}")
263
272
 
264
273
  run_callbacks(:on_failure)
265
274
  raise @error if should_raise_on_failure?
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.12.1"
9
+ VERSION = "5.13.1"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pindo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.12.1
4
+ version: 5.13.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -315,7 +315,6 @@ files:
315
315
  - lib/pindo/command/android.rb
316
316
  - lib/pindo/command/android/autobuild.rb
317
317
  - lib/pindo/command/android/autoresign.rb
318
- - lib/pindo/command/android/build.rb
319
318
  - lib/pindo/command/android/keystore.rb
320
319
  - lib/pindo/command/appstore.rb
321
320
  - lib/pindo/command/appstore/adhocbuild.rb
@@ -1,186 +0,0 @@
1
- require 'highline/import'
2
- require 'fileutils'
3
- require 'json'
4
- require 'pindo/module/build/build_helper'
5
- require 'pindo/module/build/git_repo_helper'
6
- require 'pindo/module/android/android_build_helper'
7
-
8
- module Pindo
9
- class Command
10
- class Android < Command
11
- class Build < Android
12
-
13
- self.summary = '只编译APK不修改工程'
14
- self.description = <<-DESC
15
- 只编译APK不修改工程
16
-
17
- 支持功能:
18
-
19
- * 编译Android工程
20
-
21
- * 生成APK文件
22
-
23
- * 支持上传到JPS测试平台
24
-
25
- * 支持发送测试通知
26
-
27
- 使用示例:
28
-
29
- $ pindo android build # 编译APK
30
-
31
- $ pindo android build --upload # 编译并上传到JPS
32
-
33
- $ pindo android build --send # 编译、上传并发送通知
34
-
35
- $ pindo android build --proj="My App" # 指定项目名称
36
- DESC
37
-
38
- def self.options
39
- [
40
- ['--proj', '指定上传到测试平台的项目名称'],
41
- ['--upload', '上传编译后的apk到测试平台'],
42
- ['--send', '上传成功后发送测试通知'],
43
- ].concat(super)
44
- end
45
-
46
- def initialize(argv)
47
- @args_upload_flag = argv.flag?('upload', false)
48
- @args_send_flag = argv.flag?('send', false)
49
- @args_proj_name = argv.option('proj')
50
-
51
- if @args_send_flag
52
- @args_upload_flag = true
53
- end
54
-
55
- super
56
- @additional_args = argv.remainder!
57
- end
58
-
59
- def run
60
-
61
- pindo_project_dir = Dir.pwd
62
-
63
- build_helper = Pindo::BuildHelper.share_instance
64
- project_type = build_helper.project_type(pindo_project_dir)
65
-
66
- args_temp = []
67
- args_temp << "--proj=#{@args_proj_name}" if @args_proj_name
68
- args_temp << "--upload" if @args_upload_flag
69
- args_temp << "--send" if @args_send_flag
70
- case project_type
71
- when :ios
72
- raise Informative, "iOS 工程, 请使用 pindo ios build"
73
- when :android
74
- android_build
75
- when :unity
76
- raise Informative, "Unity 工程, 请使用 pindo unity apk"
77
- else
78
- raise Informative, "当前目录不是工程目录,不能编译"
79
- end
80
- end
81
-
82
- def android_build
83
- pindo_project_dir = Dir.pwd
84
- build_helper = Pindo::BuildHelper.share_instance
85
- if @args_upload_flag
86
- git_repo_helper = Pindo::GitRepoHelper.share_instance
87
- is_need_add_tag, tag_action_parms = git_repo_helper.check_is_need_add_tag?(pindo_project_dir)
88
- if is_need_add_tag
89
- git_repo_helper.create_and_push_tag(
90
- project_dir: pindo_project_dir,
91
- mode: 'minor',
92
- force_retag: tag_action_parms&.include?('--retag') || false,
93
- custom_tag: nil,
94
- release_branch: 'master'
95
- )
96
- end
97
- end
98
-
99
- app_info_obj = nil
100
- workflow_info = nil
101
- if @args_upload_flag
102
- proj_name = @args_proj_name
103
- # 传入 package_type 获取 workflow_info
104
- app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
105
- working_directory: Dir.pwd,
106
- proj_name: proj_name,
107
- package_type: 'apk'
108
- )
109
-
110
- # ===== 使用 workflow 配置更新 Android 项目 =====
111
- if workflow_info && workflow_info[:package_name]
112
- workflow_packname = workflow_info[:package_name]
113
-
114
- puts "\n使用工作流配置更新 Android 项目:"
115
- puts " Workflow Package Name: #{workflow_packname}"
116
-
117
- # 一次性更新 App Name、Application ID 和 URL Schemes
118
- Pindo::AndroidConfigHelper.update_project_with_workflow(
119
- project_dir: pindo_project_dir,
120
- workflow_packname: workflow_packname
121
- )
122
-
123
- # 添加基于 Application ID 的 Scheme(在 workflow 设置完成后)
124
- Pindo::AndroidConfigHelper.add_application_id_based_scheme(
125
- project_dir: pindo_project_dir
126
- )
127
- else
128
- raise Informative, "未获取到工作流信息"
129
- end
130
- end
131
-
132
-
133
- android_build_helper = Pindo::AndroidBuildHelper.share_instance
134
-
135
- begin
136
- apk_path = android_build_helper.auto_build_apk(pindo_project_dir, !@args_release_flag)
137
- ipa_file_upload = Dir.glob(apk_path).max_by {|f| File.mtime(f)}
138
-
139
- if !ipa_file_upload.nil? && !app_info_obj.nil?
140
-
141
- description = nil
142
- result_data = PgyerHelper.share_instace.start_upload(
143
- app_info_obj: app_info_obj,
144
- ipa_file_upload: ipa_file_upload,
145
- description: description,
146
- workflow_info: workflow_info
147
- )
148
- if !result_data.nil? && !result_data["data"].nil? && !result_data["data"]["id"].nil?
149
- PgyerHelper.share_instace.print_app_version_info(
150
- app_info_obj: app_info_obj,
151
- app_version_info_obj: result_data["data"]
152
- )
153
- if @args_send_flag
154
- # 始终发送给自己
155
- PgyerHelper.share_instace.send_apptest_msg(
156
- app_info_obj: app_info_obj,
157
- app_version_info_obj: result_data["data"],
158
- receiveType: "self"
159
- )
160
-
161
- # 额外发送到测试群
162
- PgyerHelper.share_instace.send_apptest_msg(
163
- app_info_obj: app_info_obj,
164
- app_version_info_obj: result_data["data"],
165
- chatEnv: "DevTest",
166
- receiveType: "chat"
167
- )
168
- end
169
- end
170
- end
171
-
172
- # 只在构建成功完成时弹出目标文件夹
173
- puts "\e[32m构建完成!正在打开目标文件夹...\e[0m"
174
- system "open #{pindo_project_dir}"
175
-
176
- rescue => e
177
- puts "\e[31m构建失败: #{e.message}\e[0m"
178
- puts "\e[33m正在打开项目文件夹以便检查错误...\e[0m"
179
- system "open #{pindo_project_dir}"
180
- raise e
181
- end
182
- end
183
- end
184
- end
185
- end
186
- end