mysigner 0.1.2 → 0.1.4

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.githooks/pre-commit +15 -0
  3. data/.githooks/pre-push +21 -0
  4. data/.github/workflows/ci.yml +29 -0
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +55 -0
  7. data/.rubocop_todo.yml +126 -0
  8. data/CHANGELOG.md +96 -0
  9. data/Gemfile +5 -3
  10. data/Gemfile.lock +38 -8
  11. data/README.md +14 -16
  12. data/Rakefile +5 -3
  13. data/bin/console +4 -3
  14. data/bin/setup +3 -0
  15. data/certificate_.cer +0 -0
  16. data/exe/mysigner +19 -2
  17. data/iOS_App_Store_Profile.mobileprovision +1 -0
  18. data/iOS_Distribution_Certificate.cer +1 -0
  19. data/lib/mysigner/build/android_executor.rb +83 -63
  20. data/lib/mysigner/build/android_parser.rb +33 -40
  21. data/lib/mysigner/build/configurator.rb +17 -16
  22. data/lib/mysigner/build/detector.rb +39 -50
  23. data/lib/mysigner/build/error_analyzer.rb +70 -68
  24. data/lib/mysigner/build/executor.rb +30 -37
  25. data/lib/mysigner/build/parser.rb +18 -18
  26. data/lib/mysigner/cleanup/private_keys_purger.rb +41 -0
  27. data/lib/mysigner/cli/auth_commands.rb +771 -764
  28. data/lib/mysigner/cli/build_commands.rb +962 -796
  29. data/lib/mysigner/cli/concerns/actionable_suggestions.rb +208 -154
  30. data/lib/mysigner/cli/concerns/api_helpers.rb +46 -54
  31. data/lib/mysigner/cli/concerns/error_handlers.rb +247 -237
  32. data/lib/mysigner/cli/concerns/helpers.rb +44 -1
  33. data/lib/mysigner/cli/diagnostic_commands.rb +667 -636
  34. data/lib/mysigner/cli/resource_commands.rb +1153 -985
  35. data/lib/mysigner/cli/validate_commands.rb +25 -25
  36. data/lib/mysigner/cli.rb +11 -1
  37. data/lib/mysigner/client.rb +27 -19
  38. data/lib/mysigner/config.rb +161 -60
  39. data/lib/mysigner/export/exporter.rb +38 -37
  40. data/lib/mysigner/signing/certificate_checker.rb +18 -23
  41. data/lib/mysigner/signing/gradle_signing_injector.rb +67 -0
  42. data/lib/mysigner/signing/keystore_manager.rb +81 -61
  43. data/lib/mysigner/signing/validator.rb +38 -40
  44. data/lib/mysigner/signing/wizard.rb +329 -342
  45. data/lib/mysigner/upload/app_store_automation.rb +96 -49
  46. data/lib/mysigner/upload/app_store_submission.rb +87 -92
  47. data/lib/mysigner/upload/asc_rest_uploader.rb +119 -0
  48. data/lib/mysigner/upload/play_store_uploader.rb +164 -144
  49. data/lib/mysigner/upload/uploader.rb +136 -115
  50. data/lib/mysigner/version.rb +3 -1
  51. data/lib/mysigner.rb +13 -11
  52. data/mysigner.gemspec +36 -33
  53. data/profile_.mobileprovision +0 -0
  54. data/test_manual.rb +37 -36
  55. metadata +44 -17
  56. data/.DS_Store +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mysigner
2
4
  module Build
3
5
  class Detector
@@ -9,9 +11,7 @@ module Mysigner
9
11
  # @param platform [Symbol, nil] Force detection for specific platform (:ios, :android, or nil for auto-detect iOS)
10
12
  def self.detect(directory = Dir.pwd, platform: nil)
11
13
  # If platform is explicitly android, detect android
12
- if platform == :android
13
- return detect_android(directory)
14
- end
14
+ return detect_android(directory) if platform == :android
15
15
 
16
16
  # Default behavior: detect iOS (backwards compatible)
17
17
  detect_ios(directory)
@@ -21,7 +21,7 @@ module Mysigner
21
21
  # Returns: { platform: :android, type: :gradle, path: String, framework: :capacitor/:react_native/:flutter/:native }
22
22
  def self.detect_android(directory = Dir.pwd)
23
23
  # 1. Check for Capacitor (most specific first)
24
- if File.exist?("#{directory}/capacitor.config.json") ||
24
+ if File.exist?("#{directory}/capacitor.config.json") ||
25
25
  File.exist?("#{directory}/capacitor.config.ts")
26
26
  return detect_capacitor_android(directory)
27
27
  end
@@ -34,21 +34,21 @@ module Mysigner
34
34
  # Auto-run expo prebuild
35
35
  puts "\nšŸ“¦ Expo managed workflow detected (no android/ folder)"
36
36
  puts "šŸ”§ Running: npx expo prebuild --platform android\n\n"
37
-
37
+
38
38
  result = system("cd #{directory} && npx expo prebuild --platform android")
39
-
39
+
40
40
  unless result && Dir.exist?("#{directory}/android")
41
41
  raise NoProjectError, <<~ERROR
42
42
  Failed to generate Android project with expo prebuild.
43
-
43
+
44
44
  Try running manually:
45
45
  npx expo prebuild --platform android
46
-
46
+
47
47
  Alternative: Use EAS Build (Expo's cloud service)
48
48
  Learn more: https://docs.expo.dev/bare/overview/
49
49
  ERROR
50
50
  end
51
-
51
+
52
52
  puts "\nāœ“ Android project generated successfully\n\n"
53
53
  end
54
54
  end
@@ -56,15 +56,11 @@ module Mysigner
56
56
  # 3. Check for React Native
57
57
  if File.exist?("#{directory}/package.json") && Dir.exist?("#{directory}/android")
58
58
  content = File.read("#{directory}/package.json")
59
- if content.include?('react-native')
60
- return detect_react_native_android(directory)
61
- end
59
+ return detect_react_native_android(directory) if content.include?('react-native')
62
60
  end
63
61
 
64
62
  # 3. Check for Flutter
65
- if File.exist?("#{directory}/pubspec.yaml")
66
- return detect_flutter_android(directory)
67
- end
63
+ return detect_flutter_android(directory) if File.exist?("#{directory}/pubspec.yaml")
68
64
 
69
65
  # 4. Check for .NET MAUI / Xamarin
70
66
  maui_project = Dir.glob("#{directory}/*.csproj").first
@@ -81,8 +77,6 @@ module Mysigner
81
77
  app_gradle_kts = "#{directory}/app/build.gradle.kts"
82
78
  root_gradle = "#{directory}/build.gradle"
83
79
  root_gradle_kts = "#{directory}/build.gradle.kts"
84
- settings_gradle = "#{directory}/settings.gradle"
85
- settings_gradle_kts = "#{directory}/settings.gradle.kts"
86
80
 
87
81
  if File.exist?(app_gradle) || File.exist?(app_gradle_kts)
88
82
  return {
@@ -119,7 +113,7 @@ module Mysigner
119
113
  # Detect iOS project in directory (original detect behavior)
120
114
  def self.detect_ios(directory = Dir.pwd)
121
115
  # 1. Check for Capacitor (most specific first)
122
- if File.exist?("#{directory}/capacitor.config.json") ||
116
+ if File.exist?("#{directory}/capacitor.config.json") ||
123
117
  File.exist?("#{directory}/capacitor.config.ts")
124
118
  return detect_capacitor(directory)
125
119
  end
@@ -132,21 +126,21 @@ module Mysigner
132
126
  # Auto-run expo prebuild
133
127
  puts "\nšŸ“¦ Expo managed workflow detected (no ios/ folder)"
134
128
  puts "šŸ”§ Running: npx expo prebuild --platform ios\n\n"
135
-
129
+
136
130
  result = system("cd #{directory} && npx expo prebuild --platform ios")
137
-
131
+
138
132
  unless result && Dir.exist?("#{directory}/ios")
139
133
  raise NoProjectError, <<~ERROR
140
134
  Failed to generate iOS project with expo prebuild.
141
-
135
+
142
136
  Try running manually:
143
137
  npx expo prebuild --platform ios
144
-
138
+
145
139
  Alternative: Use EAS Build (Expo's cloud service)
146
140
  Learn more: https://docs.expo.dev/bare/overview/
147
141
  ERROR
148
142
  end
149
-
143
+
150
144
  puts "\nāœ“ iOS project generated successfully\n\n"
151
145
  end
152
146
  end
@@ -154,15 +148,11 @@ module Mysigner
154
148
  # 3. Check for React Native
155
149
  if File.exist?("#{directory}/package.json") && Dir.exist?("#{directory}/ios")
156
150
  content = File.read("#{directory}/package.json")
157
- if content.include?('react-native')
158
- return detect_react_native(directory)
159
- end
151
+ return detect_react_native(directory) if content.include?('react-native')
160
152
  end
161
153
 
162
154
  # 4. Check for Flutter
163
- if File.exist?("#{directory}/pubspec.yaml")
164
- return detect_flutter(directory)
165
- end
155
+ return detect_flutter(directory) if File.exist?("#{directory}/pubspec.yaml")
166
156
 
167
157
  # 5. Check for native iOS project (workspace first, then project)
168
158
  workspace = Dir.glob("#{directory}/*.xcworkspace").first
@@ -187,18 +177,18 @@ module Mysigner
187
177
  }
188
178
  end
189
179
 
190
- raise NoProjectError, "No Xcode project found in #{directory}. Run in a project directory or try 'mysigner init' first."
180
+ raise NoProjectError,
181
+ "No Xcode project found in #{directory}. Run in a project directory or try 'mysigner init' first."
191
182
  end
192
183
 
193
- private
194
-
195
184
  # Android detection for cross-platform frameworks
196
185
 
197
186
  def self.detect_capacitor_android(directory)
198
187
  android_dir = "#{directory}/android"
199
-
188
+
200
189
  unless Dir.exist?(android_dir)
201
- raise NoProjectError, "Capacitor project detected but no android/ folder found. Run 'npx cap add android' first."
190
+ raise NoProjectError,
191
+ "Capacitor project detected but no android/ folder found. Run 'npx cap add android' first."
202
192
  end
203
193
 
204
194
  app_gradle = "#{android_dir}/app/build.gradle"
@@ -216,7 +206,8 @@ module Mysigner
216
206
  }
217
207
  end
218
208
 
219
- raise NoProjectError, "Capacitor project detected but no Android build.gradle found. Run 'npx cap sync android' first."
209
+ raise NoProjectError,
210
+ "Capacitor project detected but no Android build.gradle found. Run 'npx cap sync android' first."
220
211
  end
221
212
 
222
213
  def self.detect_react_native_android(directory)
@@ -237,15 +228,13 @@ module Mysigner
237
228
  }
238
229
  end
239
230
 
240
- raise NoProjectError, "React Native project detected but no Android build.gradle found in android/ directory."
231
+ raise NoProjectError, 'React Native project detected but no Android build.gradle found in android/ directory.'
241
232
  end
242
233
 
243
234
  def self.detect_flutter_android(directory)
244
235
  android_dir = "#{directory}/android"
245
236
 
246
- unless Dir.exist?(android_dir)
247
- raise NoProjectError, "Flutter project detected but no android/ folder found. Run 'flutter create .' first."
248
- end
237
+ raise NoProjectError, "Flutter project detected but no android/ folder found. Run 'flutter create .' first." unless Dir.exist?(android_dir)
249
238
 
250
239
  app_gradle = "#{android_dir}/app/build.gradle"
251
240
  app_gradle_kts = "#{android_dir}/app/build.gradle.kts"
@@ -262,19 +251,20 @@ module Mysigner
262
251
  }
263
252
  end
264
253
 
265
- raise NoProjectError, "Flutter project detected but no Android build.gradle found. Run 'flutter build apk' first."
254
+ raise NoProjectError,
255
+ "Flutter project detected but no Android build.gradle found. Run 'flutter build apk' first."
266
256
  end
267
257
 
268
258
  def self.detect_dotnet_android(directory, csproj_path)
269
259
  content = File.read(csproj_path)
270
-
260
+
271
261
  framework_type = if content.include?('Maui')
272
- :maui
273
- elsif content.include?('Xamarin.Forms')
274
- :xamarin_forms
275
- else
276
- :xamarin
277
- end
262
+ :maui
263
+ elsif content.include?('Xamarin.Forms')
264
+ :xamarin_forms
265
+ else
266
+ :xamarin
267
+ end
278
268
 
279
269
  {
280
270
  platform: :android,
@@ -291,7 +281,7 @@ module Mysigner
291
281
 
292
282
  def self.detect_capacitor(directory)
293
283
  ios_dir = "#{directory}/ios/App"
294
-
284
+
295
285
  # Capacitor always creates App.xcworkspace
296
286
  workspace = "#{ios_dir}/App.xcworkspace"
297
287
  project = "#{ios_dir}/App.xcodeproj"
@@ -348,7 +338,7 @@ module Mysigner
348
338
  }
349
339
  end
350
340
 
351
- raise NoProjectError, "React Native project detected but no Xcode project found in ios/ directory."
341
+ raise NoProjectError, 'React Native project detected but no Xcode project found in ios/ directory.'
352
342
  end
353
343
 
354
344
  def self.detect_flutter(directory)
@@ -385,4 +375,3 @@ module Mysigner
385
375
  end
386
376
  end
387
377
  end
388
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mysigner
2
4
  module Build
3
5
  class ErrorAnalyzer
@@ -18,11 +20,11 @@ module Mysigner
18
20
  return nil unless any_issues?
19
21
 
20
22
  lines = []
21
- lines << ""
22
- lines << "=" * 70
23
- lines << " šŸ’” SUGGESTIONS: How to fix these build errors"
24
- lines << "=" * 70
25
- lines << ""
23
+ lines << ''
24
+ lines << ('=' * 70)
25
+ lines << ' šŸ’” SUGGESTIONS: How to fix these build errors'
26
+ lines << ('=' * 70)
27
+ lines << ''
26
28
 
27
29
  # Group issues by type for cleaner output
28
30
  profile_issues = @issues.select { |i| i[:type] == :profile_capability }
@@ -31,8 +33,8 @@ module Mysigner
31
33
 
32
34
  # Profile capability issues
33
35
  if profile_issues.any?
34
- lines << " šŸ“‹ PROVISIONING PROFILE ISSUES"
35
- lines << ""
36
+ lines << ' šŸ“‹ PROVISIONING PROFILE ISSUES'
37
+ lines << ''
36
38
 
37
39
  # Group by profile name
38
40
  by_profile = profile_issues.group_by { |i| i[:profile_name] }
@@ -40,70 +42,70 @@ module Mysigner
40
42
  capabilities = issues.map { |i| i[:capability] }.compact.uniq
41
43
  lines << " Profile: \"#{profile_name}\""
42
44
  lines << " Missing capabilities: #{capabilities.join(', ')}"
43
- lines << ""
45
+ lines << ''
44
46
  end
45
47
 
46
- lines << " How to fix:"
47
- lines << " 1. Go to Apple Developer Portal → Certificates, Identifiers & Profiles"
48
+ lines << ' How to fix:'
49
+ lines << ' 1. Go to Apple Developer Portal → Certificates, Identifiers & Profiles'
48
50
  lines << " 2. Select 'Identifiers' and find your Bundle ID"
49
- lines << " 3. Enable the missing capabilities (App Groups, Apple Pay, etc.)"
50
- lines << " 4. If adding App Groups or Merchant IDs, make sure to select the specific identifiers"
51
+ lines << ' 3. Enable the missing capabilities (App Groups, Apple Pay, etc.)'
52
+ lines << ' 4. If adding App Groups or Merchant IDs, make sure to select the specific identifiers'
51
53
  lines << " 5. Go to 'Profiles' and regenerate the affected provisioning profiles"
52
- lines << " 6. Download new profiles: mysigner sync ios && mysigner profile download <ID>"
53
- lines << " 7. Install profiles to: ~/Library/MobileDevice/Provisioning Profiles/"
54
- lines << ""
54
+ lines << ' 6. Download new profiles: mysigner sync ios && mysigner profile download <ID>'
55
+ lines << ' 7. Install profiles to: ~/Library/MobileDevice/Provisioning Profiles/'
56
+ lines << ''
55
57
  end
56
58
 
57
59
  # Missing specific identifiers (App Group ID, Merchant ID)
58
60
  if identifier_issues.any?
59
- lines << " šŸ”— MISSING IDENTIFIERS"
60
- lines << ""
61
+ lines << ' šŸ”— MISSING IDENTIFIERS'
62
+ lines << ''
61
63
 
62
64
  identifier_issues.each do |issue|
63
65
  lines << " Profile: \"#{issue[:profile_name]}\""
64
66
  lines << " Missing: #{issue[:identifier_type]} - #{issue[:identifier]}"
65
- lines << ""
67
+ lines << ''
66
68
  end
67
69
 
68
- lines << " How to fix:"
69
- lines << " 1. Go to Apple Developer Portal → Identifiers"
70
- lines << " 2. Find your Bundle ID and edit it"
71
- lines << " 3. Under the capability, add/select the specific identifier:"
72
- lines << " • For App Groups: select your group.* identifier"
73
- lines << " • For Apple Pay: select your merchant.* identifier"
74
- lines << " 4. Regenerate the provisioning profile"
75
- lines << ""
70
+ lines << ' How to fix:'
71
+ lines << ' 1. Go to Apple Developer Portal → Identifiers'
72
+ lines << ' 2. Find your Bundle ID and edit it'
73
+ lines << ' 3. Under the capability, add/select the specific identifier:'
74
+ lines << ' • For App Groups: select your group.* identifier'
75
+ lines << ' • For Apple Pay: select your merchant.* identifier'
76
+ lines << ' 4. Regenerate the provisioning profile'
77
+ lines << ''
76
78
  end
77
79
 
78
80
  # Certificate mismatch
79
81
  if cert_issues.any?
80
- lines << " šŸ” CERTIFICATE MISMATCH"
81
- lines << ""
82
- lines << " Your app and its extensions are signed with different certificates."
83
- lines << ""
84
- lines << " How to fix:"
85
- lines << " 1. Open your Xcode project"
86
- lines << " 2. For EACH target (main app AND extensions):"
87
- lines << " • Select the target → Signing & Capabilities"
88
- lines << " • Ensure all targets use the same signing identity:"
82
+ lines << ' šŸ” CERTIFICATE MISMATCH'
83
+ lines << ''
84
+ lines << ' Your app and its extensions are signed with different certificates.'
85
+ lines << ''
86
+ lines << ' How to fix:'
87
+ lines << ' 1. Open your Xcode project'
88
+ lines << ' 2. For EACH target (main app AND extensions):'
89
+ lines << ' • Select the target → Signing & Capabilities'
90
+ lines << ' • Ensure all targets use the same signing identity:'
89
91
  lines << " - For App Store: 'Apple Distribution'"
90
92
  lines << " - For Development: 'Apple Development'"
91
- lines << " 3. Make sure all targets use matching profile types:"
92
- lines << " • App Store profiles for App Store builds"
93
- lines << " • Development profiles for development builds"
94
- lines << ""
95
- lines << " Quick fix for App Store builds:"
96
- lines << " In project.pbxproj, ensure Release configuration has:"
97
- lines << " CODE_SIGN_IDENTITY = \"Apple Distribution\""
98
- lines << " PROVISIONING_PROFILE_SPECIFIER = \"YourApp App Store\""
99
- lines << ""
93
+ lines << ' 3. Make sure all targets use matching profile types:'
94
+ lines << ' • App Store profiles for App Store builds'
95
+ lines << ' • Development profiles for development builds'
96
+ lines << ''
97
+ lines << ' Quick fix for App Store builds:'
98
+ lines << ' In project.pbxproj, ensure Release configuration has:'
99
+ lines << ' CODE_SIGN_IDENTITY = "Apple Distribution"'
100
+ lines << ' PROVISIONING_PROFILE_SPECIFIER = "YourApp App Store"'
101
+ lines << ''
100
102
  end
101
103
 
102
- lines << " šŸ“š More help:"
104
+ lines << ' šŸ“š More help:'
103
105
  lines << " • Run 'mysigner doctor' to check your setup"
104
106
  lines << " • Run 'mysigner profiles' to list available profiles"
105
- lines << " • Check My Signer dashboard for Bundle ID capabilities"
106
- lines << ""
107
+ lines << ' • Check My Signer dashboard for Bundle ID capabilities'
108
+ lines << ''
107
109
 
108
110
  lines.join("\n")
109
111
  end
@@ -118,10 +120,10 @@ module Mysigner
118
120
 
119
121
  def analyze_error(error)
120
122
  # Normalize curly quotes to straight quotes
121
- error = error.gsub(/["""]/, '"').gsub(/[''']/, "'")
123
+ error = error.gsub('"', '"').gsub('\'', "'")
122
124
 
123
125
  # Pattern: Provisioning profile "X" doesn't include the Y capability
124
- if match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) include the (.+?) capability/i)
126
+ if (match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) include the (.+?) capability/i))
125
127
  @issues << {
126
128
  type: :profile_capability,
127
129
  profile_name: match[1],
@@ -130,27 +132,27 @@ module Mysigner
130
132
  end
131
133
 
132
134
  # Pattern: Provisioning profile "X" doesn't support the Y App Group
133
- if match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) support the (.+?) App Group/i)
135
+ if (match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) support the (.+?) App Group/i))
134
136
  @issues << {
135
137
  type: :missing_identifier,
136
138
  profile_name: match[1],
137
- identifier_type: "App Group",
139
+ identifier_type: 'App Group',
138
140
  identifier: match[2].strip
139
141
  }
140
142
  end
141
143
 
142
144
  # Pattern: Provisioning profile "X" doesn't support the Y Merchant ID
143
- if match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) support the (.+?) Merchant ID/i)
145
+ if (match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) support the (.+?) Merchant ID/i))
144
146
  @issues << {
145
147
  type: :missing_identifier,
146
148
  profile_name: match[1],
147
- identifier_type: "Merchant ID",
149
+ identifier_type: 'Merchant ID',
148
150
  identifier: match[2].strip
149
151
  }
150
152
  end
151
153
 
152
154
  # Pattern: Provisioning profile "X" doesn't match the entitlements file's value
153
- if match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) match.*entitlements.*?for the (.+?) entitlement/i)
155
+ if (match = error.match(/Provisioning profile "([^"]+)".*(?:doesn't|does not) match.*entitlements.*?for the (.+?) entitlement/i))
154
156
  capability = entitlement_to_capability(match[2])
155
157
  @issues << {
156
158
  type: :profile_capability,
@@ -160,7 +162,7 @@ module Mysigner
160
162
  end
161
163
 
162
164
  # Pattern: Embedded binary is not signed with the same certificate
163
- if error.include?("Embedded binary is not signed with the same certificate")
165
+ if error.include?('Embedded binary is not signed with the same certificate')
164
166
  @issues << {
165
167
  type: :certificate_mismatch,
166
168
  message: error
@@ -168,23 +170,23 @@ module Mysigner
168
170
  end
169
171
 
170
172
  # Pattern: Code Sign error
171
- if error.include?("Code Sign error")
172
- @issues << {
173
- type: :code_sign_error,
174
- message: error
175
- }
176
- end
173
+ return unless error.include?('Code Sign error')
174
+
175
+ @issues << {
176
+ type: :code_sign_error,
177
+ message: error
178
+ }
177
179
  end
178
180
 
179
181
  def entitlement_to_capability(entitlement)
180
182
  mappings = {
181
- "com.apple.security.application-groups" => "App Groups",
182
- "com.apple.developer.in-app-payments" => "Apple Pay",
183
- "aps-environment" => "Push Notifications",
184
- "com.apple.developer.associated-domains" => "Associated Domains",
185
- "com.apple.developer.applesignin" => "Sign in with Apple",
186
- "com.apple.developer.icloud-services" => "iCloud",
187
- "com.apple.developer.healthkit" => "HealthKit"
183
+ 'com.apple.security.application-groups' => 'App Groups',
184
+ 'com.apple.developer.in-app-payments' => 'Apple Pay',
185
+ 'aps-environment' => 'Push Notifications',
186
+ 'com.apple.developer.associated-domains' => 'Associated Domains',
187
+ 'com.apple.developer.applesignin' => 'Sign in with Apple',
188
+ 'com.apple.developer.icloud-services' => 'iCloud',
189
+ 'com.apple.developer.healthkit' => 'HealthKit'
188
190
  }
189
191
  mappings[entitlement] || entitlement
190
192
  end
@@ -1,5 +1,6 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'English'
3
4
  module Mysigner
4
5
  module Build
5
6
  class Executor
@@ -20,7 +21,8 @@ module Mysigner
20
21
  # - team_id: Development team ID to override project setting
21
22
  # - bundle_id: Bundle ID to override project setting
22
23
  # - skip_extensions: If true, disable code signing for extension targets
23
- def build!(target_name = nil, configuration = 'Release', scheme: nil, signing_style: nil, team_id: nil, bundle_id: nil, skip_extensions: false)
24
+ def build!(target_name = nil, configuration = 'Release', scheme: nil, signing_style: nil, team_id: nil,
25
+ bundle_id: nil, skip_extensions: false)
24
26
  target = target_name || @parser.main_target.name
25
27
  scheme_name = scheme || target
26
28
  @signing_style = signing_style
@@ -31,7 +33,7 @@ module Mysigner
31
33
  # Use Xcode's default DerivedData location to keep project clean
32
34
  # This matches Xcode's behavior and avoids polluting the project directory
33
35
  output_dir = File.join(@project_info[:directory], 'build')
34
- FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir)
36
+ FileUtils.mkdir_p(output_dir)
35
37
 
36
38
  # Generate archive path with timestamp
37
39
  timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
@@ -44,14 +46,10 @@ module Mysigner
44
46
  # Execute build
45
47
  success = execute_with_output(cmd)
46
48
 
47
- unless success
48
- raise BuildError, "Build failed. Check output above for errors."
49
- end
49
+ raise BuildError, 'Build failed. Check output above for errors.' unless success
50
50
 
51
51
  # Verify archive was created
52
- unless File.exist?(archive_path)
53
- raise BuildError, "Build reported success but archive not found at: #{archive_path}"
54
- end
52
+ raise BuildError, "Build reported success but archive not found at: #{archive_path}" unless File.exist?(archive_path)
55
53
 
56
54
  archive_path
57
55
  end
@@ -59,14 +57,14 @@ module Mysigner
59
57
  private
60
58
 
61
59
  def build_command(scheme, configuration, archive_path)
62
- cmd = ['xcodebuild', 'archive']
60
+ cmd = %w[xcodebuild archive]
63
61
 
64
62
  # Workspace or project
65
- if @project_info[:type] == :workspace
66
- cmd += ['-workspace', @project_info[:path]]
67
- else
68
- cmd += ['-project', @project_info[:path]]
69
- end
63
+ cmd += if @project_info[:type] == :workspace
64
+ ['-workspace', @project_info[:path]]
65
+ else
66
+ ['-project', @project_info[:path]]
67
+ end
70
68
 
71
69
  # Scheme and configuration
72
70
  cmd += [
@@ -78,26 +76,22 @@ module Mysigner
78
76
  # SDK selection based on platform
79
77
  platform = @parser.target_platform(scheme)
80
78
  sdk = case platform
81
- when :macos
82
- 'macosx'
83
- when :tvos
84
- 'appletvos'
85
- when :watchos
86
- 'watchos'
87
- else
88
- 'iphoneos' # default to iOS
89
- end
79
+ when :macos
80
+ 'macosx'
81
+ when :tvos
82
+ 'appletvos'
83
+ when :watchos
84
+ 'watchos'
85
+ else
86
+ 'iphoneos' # default to iOS
87
+ end
90
88
  cmd += ['-sdk', sdk]
91
89
 
92
90
  # Override team ID if provided
93
- if @team_id
94
- cmd += ["DEVELOPMENT_TEAM=#{@team_id}"]
95
- end
96
-
91
+ cmd += ["DEVELOPMENT_TEAM=#{@team_id}"] if @team_id
92
+
97
93
  # Override bundle ID if provided
98
- if @bundle_id
99
- cmd += ["PRODUCT_BUNDLE_IDENTIFIER=#{@bundle_id}"]
100
- end
94
+ cmd += ["PRODUCT_BUNDLE_IDENTIFIER=#{@bundle_id}"] if @bundle_id
101
95
 
102
96
  # Handle signing based on style
103
97
  case @signing_style
@@ -131,13 +125,13 @@ module Mysigner
131
125
  end
132
126
 
133
127
  def execute_with_output(cmd)
134
- puts "šŸ—ļø Running: xcodebuild archive..."
135
- puts ""
128
+ puts 'šŸ—ļø Running: xcodebuild archive...'
129
+ puts ''
136
130
 
137
131
  @build_errors = []
138
132
 
139
133
  # Run command and capture output in real-time
140
- IO.popen(cmd, err: [:child, :out]) do |io|
134
+ IO.popen(cmd, err: %i[child out]) do |io|
141
135
  io.each_line do |line|
142
136
  # Filter output to show only important messages
143
137
  next if line.strip.empty?
@@ -166,11 +160,10 @@ module Mysigner
166
160
  end
167
161
  end
168
162
 
169
- puts "" # New line after dots
163
+ puts '' # New line after dots
170
164
 
171
- $?.success?
165
+ $CHILD_STATUS.success?
172
166
  end
173
167
  end
174
168
  end
175
169
  end
176
-