mysigner 0.3.1 → 0.3.2
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/CHANGELOG.md +19 -0
- data/Gemfile.lock +1 -1
- data/README.md +16 -0
- data/exe/mysigner +36 -1
- data/lib/mysigner/build/android_executor.rb +101 -29
- data/lib/mysigner/build/android_parser.rb +2 -2
- data/lib/mysigner/build/detector.rb +122 -53
- data/lib/mysigner/cli/auth_commands.rb +109 -6
- data/lib/mysigner/cli/build_commands.rb +24 -9
- data/lib/mysigner/cli/concerns/error_handlers.rb +9 -12
- data/lib/mysigner/cli/concerns/helpers.rb +37 -0
- data/lib/mysigner/cli/diagnostic_commands.rb +67 -29
- data/lib/mysigner/cli/resource_commands.rb +72 -27
- data/lib/mysigner/cli/validate_commands.rb +16 -1
- data/lib/mysigner/config.rb +14 -2
- data/lib/mysigner/signing/gradle_signing_injector.rb +14 -0
- data/lib/mysigner/version.rb +1 -1
- data/mysigner.gemspec +13 -8
- metadata +11 -10
|
@@ -1393,6 +1393,8 @@ module Mysigner
|
|
|
1393
1393
|
|
|
1394
1394
|
mysigner android build
|
|
1395
1395
|
Build an AAB file for upload to Google Play Console.
|
|
1396
|
+
(An AAB — Android App Bundle, .aab — is the format Google Play
|
|
1397
|
+
requires; the CLI builds and signs it for you, not an APK.)
|
|
1396
1398
|
Use this for your FIRST upload (required before mysigner ship works).
|
|
1397
1399
|
|
|
1398
1400
|
mysigner android list
|
|
@@ -1731,8 +1733,12 @@ module Mysigner
|
|
|
1731
1733
|
if keystore_info
|
|
1732
1734
|
say "🔐 Keystore: #{keystore_info[:name]}", :green
|
|
1733
1735
|
else
|
|
1734
|
-
say '⚠️ No keystore configured
|
|
1735
|
-
say
|
|
1736
|
+
say '⚠️ No release keystore configured — building a DEBUG-SIGNED AAB.', :yellow
|
|
1737
|
+
say ' A debug-signed AAB is fine for local install/testing but Google', :yellow
|
|
1738
|
+
say ' Play will REJECT it on upload. To produce a publishable build:', :yellow
|
|
1739
|
+
say ' • Vault mode: mysigner android init (set up release signing)', :yellow
|
|
1740
|
+
say ' • Local-only mode: pass --keystore-path / --keystore-password to', :yellow
|
|
1741
|
+
say ' `mysigner ship … --platform android`', :yellow
|
|
1736
1742
|
end
|
|
1737
1743
|
say ''
|
|
1738
1744
|
say '⏱️ This may take a few minutes...', :yellow
|
|
@@ -1778,16 +1784,21 @@ module Mysigner
|
|
|
1778
1784
|
say ' mysigner ship internal --platform android', :green
|
|
1779
1785
|
say ''
|
|
1780
1786
|
|
|
1781
|
-
# Open the folder containing the AAB
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1787
|
+
# Open the folder containing the AAB — only in an interactive
|
|
1788
|
+
# terminal. On headless / CI / SSH there is no file manager, and
|
|
1789
|
+
# xdg-open/explorer would spew errors AFTER a successful build.
|
|
1790
|
+
if $stdout.tty?
|
|
1791
|
+
aab_dir = File.dirname(aab_path)
|
|
1792
|
+
opener = case RUBY_PLATFORM
|
|
1793
|
+
when /darwin/ then 'open'
|
|
1794
|
+
when /linux/ then 'xdg-open'
|
|
1795
|
+
when /mingw|mswin/ then 'explorer'
|
|
1796
|
+
end
|
|
1797
|
+
if opener
|
|
1798
|
+
say '📂 Opening folder...', :yellow
|
|
1799
|
+
target = opener == 'explorer' ? aab_dir.gsub('/', '\\') : aab_dir
|
|
1800
|
+
system(opener, target, %i[out err] => File::NULL)
|
|
1801
|
+
end
|
|
1791
1802
|
end
|
|
1792
1803
|
rescue Build::Detector::NoProjectError => e
|
|
1793
1804
|
error e.message
|
|
@@ -1899,12 +1910,19 @@ module Mysigner
|
|
|
1899
1910
|
# Write modified app.json
|
|
1900
1911
|
File.write(app_json_path, JSON.pretty_generate(config))
|
|
1901
1912
|
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1913
|
+
# Back up an existing android/ so a failed prebuild can't destroy a
|
|
1914
|
+
# committed or hand-edited native project — restored on any failure.
|
|
1915
|
+
backup_dir = nil
|
|
1916
|
+
if Dir.exist?(android_dir)
|
|
1917
|
+
# pid + timestamp so a crashed prior run (same pid reused) can't
|
|
1918
|
+
# collide and have its backup wiped by the rm_rf below.
|
|
1919
|
+
backup_dir = "#{android_dir}.mysigner-bak-#{Process.pid}-#{Time.now.to_i}"
|
|
1920
|
+
FileUtils.rm_rf(backup_dir)
|
|
1921
|
+
FileUtils.mv(android_dir, backup_dir)
|
|
1922
|
+
end
|
|
1906
1923
|
|
|
1907
|
-
|
|
1924
|
+
begin
|
|
1925
|
+
# Regenerate the native android/ from the version-bumped config.
|
|
1908
1926
|
Dir.chdir(project_dir) do
|
|
1909
1927
|
success = system('npx', 'expo', 'prebuild', '--platform', 'android', '--clean')
|
|
1910
1928
|
raise 'expo prebuild failed' unless success
|
|
@@ -1919,8 +1937,28 @@ module Mysigner
|
|
|
1919
1937
|
File.expand_path('~/Library/Android/sdk')
|
|
1920
1938
|
File.write(local_props_path, "sdk.dir=#{sdk_path}\n") if Dir.exist?(sdk_path)
|
|
1921
1939
|
end
|
|
1940
|
+
|
|
1941
|
+
# Success — drop the backup of the old android/.
|
|
1942
|
+
FileUtils.rm_rf(backup_dir) if backup_dir
|
|
1943
|
+
rescue StandardError
|
|
1944
|
+
# Restore the original android/ so a failed regeneration never
|
|
1945
|
+
# leaves the user worse off than before.
|
|
1946
|
+
if backup_dir && Dir.exist?(backup_dir)
|
|
1947
|
+
begin
|
|
1948
|
+
FileUtils.rm_rf(android_dir)
|
|
1949
|
+
FileUtils.mv(backup_dir, android_dir)
|
|
1950
|
+
rescue StandardError => restore_err
|
|
1951
|
+
# Don't let a restore failure silently strand the user's
|
|
1952
|
+
# native project inside the backup dir — tell them exactly
|
|
1953
|
+
# where it is and how to recover it.
|
|
1954
|
+
say "⚠️ Could not auto-restore your android/ folder: #{restore_err.message}", :red
|
|
1955
|
+
say " Your original android/ is preserved at: #{backup_dir}", :yellow
|
|
1956
|
+
say " Recover it with: mv '#{backup_dir}' '#{android_dir}'", :yellow
|
|
1957
|
+
end
|
|
1958
|
+
end
|
|
1959
|
+
raise
|
|
1922
1960
|
ensure
|
|
1923
|
-
#
|
|
1961
|
+
# Always restore the original app.json
|
|
1924
1962
|
File.write(app_json_path, original_content)
|
|
1925
1963
|
end
|
|
1926
1964
|
end
|
|
@@ -2116,17 +2154,23 @@ module Mysigner
|
|
|
2116
2154
|
gradle_args = ['./gradlew', 'bundleRelease', '--warning-mode=all']
|
|
2117
2155
|
gradle_args << "-PversionCode=#{version_code_override}" if version_code_override
|
|
2118
2156
|
|
|
2157
|
+
# Write the init script when we need to inject signing OR a
|
|
2158
|
+
# versionCode override (a bare -PversionCode is ignored by stock
|
|
2159
|
+
# build.gradle, so versionCode must flow through the init script).
|
|
2119
2160
|
injector = nil
|
|
2120
2161
|
env = {}
|
|
2121
|
-
if keystore_info
|
|
2162
|
+
if keystore_info || version_code_override
|
|
2122
2163
|
injector = Mysigner::Signing::GradleSigningInjector.new
|
|
2123
2164
|
init_path = injector.write_init_script!
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2165
|
+
if keystore_info
|
|
2166
|
+
env = keystore_info[:signing_env_vars] || injector.env_vars(
|
|
2167
|
+
keystore_path: keystore_info[:path],
|
|
2168
|
+
store_password: keystore_info[:password],
|
|
2169
|
+
key_password: keystore_info[:key_password],
|
|
2170
|
+
key_alias: keystore_info[:key_alias]
|
|
2171
|
+
)
|
|
2172
|
+
end
|
|
2173
|
+
env['MYSIGNER_VERSION_CODE'] = version_code_override.to_s if version_code_override
|
|
2130
2174
|
gradle_args.insert(1, '--init-script', init_path)
|
|
2131
2175
|
end
|
|
2132
2176
|
|
|
@@ -2145,9 +2189,10 @@ module Mysigner
|
|
|
2145
2189
|
# Find the AAB
|
|
2146
2190
|
aab_path = File.join(android_dir, 'app/build/outputs/bundle/release/app-release.aab')
|
|
2147
2191
|
unless File.exist?(aab_path)
|
|
2148
|
-
#
|
|
2192
|
+
# Fall back to the NEWEST matching AAB so a stale/wrong-flavor
|
|
2193
|
+
# artifact from a previous build is never returned.
|
|
2149
2194
|
alt_paths = Dir.glob(File.join(android_dir, 'app/build/outputs/bundle/*/*.aab'))
|
|
2150
|
-
aab_path = alt_paths.
|
|
2195
|
+
aab_path = alt_paths.max_by { |f| File.mtime(f) } if alt_paths.any?
|
|
2151
2196
|
end
|
|
2152
2197
|
aab_path
|
|
2153
2198
|
end
|
|
@@ -147,7 +147,22 @@ module Mysigner
|
|
|
147
147
|
say 'Running local Signing::Validator (server checks skipped in local-only mode).', :yellow
|
|
148
148
|
say ''
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
# Read-only detection: never run an expo prebuild from `validate`,
|
|
151
|
+
# and turn a genuine "no project here" into a clean error instead
|
|
152
|
+
# of a raw NoProjectError backtrace.
|
|
153
|
+
project_info = begin
|
|
154
|
+
Mysigner::Build::Detector.detect(allow_prebuild: false)
|
|
155
|
+
rescue Mysigner::Build::Detector::NoProjectError => e
|
|
156
|
+
error e.message
|
|
157
|
+
exit 1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if project_info[:needs_prebuild]
|
|
161
|
+
say 'ℹ️ Expo managed project detected — no native iOS project generated yet.', :yellow
|
|
162
|
+
say ' Run `mysigner ship` (or `npx expo prebuild`) to create it, then re-run validate.', :yellow
|
|
163
|
+
return
|
|
164
|
+
end
|
|
165
|
+
|
|
151
166
|
parser = Mysigner::Build::Parser.new(project_info)
|
|
152
167
|
target_name = parser.main_target.name
|
|
153
168
|
|
data/lib/mysigner/config.rb
CHANGED
|
@@ -251,13 +251,25 @@ module Mysigner
|
|
|
251
251
|
# Display config (with masked tokens)
|
|
252
252
|
def display
|
|
253
253
|
current_org_name = org_name(@current_organization_id) || '(not set)'
|
|
254
|
-
|
|
254
|
+
# Never let an undecryptable token turn `mysigner config` into a crash —
|
|
255
|
+
# render it as an actionable placeholder instead.
|
|
256
|
+
current_token = begin
|
|
257
|
+
api_token(@current_organization_id)
|
|
258
|
+
rescue ConfigError
|
|
259
|
+
:unreadable
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
token_display = case current_token
|
|
263
|
+
when nil then '(not set)'
|
|
264
|
+
when :unreadable then '(unreadable — run mysigner login)'
|
|
265
|
+
else mask_token(current_token)
|
|
266
|
+
end
|
|
255
267
|
|
|
256
268
|
display_data = {
|
|
257
269
|
api_url: @api_url || '(not set)',
|
|
258
270
|
user_email: @user_email || '(not set)',
|
|
259
271
|
current_organization: "#{current_org_name} (ID: #{@current_organization_id || 'not set'})",
|
|
260
|
-
current_token:
|
|
272
|
+
current_token: token_display
|
|
261
273
|
}
|
|
262
274
|
|
|
263
275
|
# Show all organizations
|
|
@@ -14,6 +14,20 @@ module Mysigner
|
|
|
14
14
|
allprojects {
|
|
15
15
|
afterEvaluate { project ->
|
|
16
16
|
if (!project.hasProperty('android')) return
|
|
17
|
+
|
|
18
|
+
// versionCode override (MySigner auto-increment). Applied here so it
|
|
19
|
+
// actually takes effect even when app/build.gradle hard-codes
|
|
20
|
+
// versionCode in defaultConfig — a plain -PversionCode project
|
|
21
|
+
// property is silently ignored by stock build.gradle files.
|
|
22
|
+
// Gate to the APPLICATION module only: com.android.library modules
|
|
23
|
+
// have no versionCode in the AGP 7/8 library DSL, so assigning it
|
|
24
|
+
// there raises. allprojects+afterEvaluate fires for every Android
|
|
25
|
+
// subproject, hence the explicit application-plugin check.
|
|
26
|
+
def vcRaw = System.getenv('MYSIGNER_VERSION_CODE')
|
|
27
|
+
if (vcRaw && vcRaw.isInteger() && project.plugins.hasPlugin('com.android.application')) {
|
|
28
|
+
project.android.defaultConfig.versionCode = vcRaw.toInteger()
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
def storePw = System.getenv('MYSIGNER_STORE_PASSWORD')
|
|
18
32
|
def keyPw = System.getenv('MYSIGNER_KEY_PASSWORD')
|
|
19
33
|
def aliasName = System.getenv('MYSIGNER_KEY_ALIAS')
|
data/lib/mysigner/version.rb
CHANGED
data/mysigner.gemspec
CHANGED
|
@@ -38,14 +38,19 @@ Gem::Specification.new do |spec|
|
|
|
38
38
|
|
|
39
39
|
\e[32m✓\e[0m You're ready to automate iOS & Android code signing.
|
|
40
40
|
|
|
41
|
-
\e[
|
|
42
|
-
• \e[
|
|
43
|
-
|
|
44
|
-
• \e[
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
\e[
|
|
41
|
+
\e[35mTwo ways to use it:\e[0m
|
|
42
|
+
• \e[1mWith a free My Signer account\e[0m (keys stored & synced for you):
|
|
43
|
+
\e[33mRun\e[0m \e[1m`mysigner onboard`\e[0m
|
|
44
|
+
• \e[1mNo account — your keys stay on this machine\e[0m (nothing sent to a server):
|
|
45
|
+
\e[33mRun\e[0m \e[1m`mysigner --local-only onboard`\e[0m
|
|
46
|
+
\e[33mNot sure? Start with --local-only.\e[0m
|
|
47
|
+
|
|
48
|
+
\e[35mAlso handy:\e[0m
|
|
49
|
+
• \e[33mRun\e[0m \e[1m`mysigner doctor`\e[0m – Check your dev environment (JDK, SDK, Xcode…)
|
|
50
|
+
• \e[33mRun\e[0m \e[1m`mysigner help`\e[0m – Explore every command
|
|
51
|
+
|
|
52
|
+
\e[35miOS (needs a Mac):\e[0m mysigner ship testflight
|
|
53
|
+
\e[35mAndroid:\e[0m mysigner ship internal --platform android
|
|
49
54
|
|
|
50
55
|
\e[36mDocs:\e[0m https://mysigner.dev/docs/commands
|
|
51
56
|
MSG
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mysigner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jurgen Leka
|
|
@@ -287,14 +287,15 @@ metadata:
|
|
|
287
287
|
rubygems_mfa_required: 'true'
|
|
288
288
|
post_install_message: "\e[36m╔══════════════════════════════════════════════════════════════╗\e[0m\n\e[36m║
|
|
289
289
|
\e[1m\U0001F680 Welcome to My Signer CLI\e[0m\e[36m ║\e[0m\n\e[36m╚══════════════════════════════════════════════════════════════╝\e[0m\n\n\e[32m✓\e[0m
|
|
290
|
-
\ You're ready to automate iOS & Android code signing.\n\n\e[
|
|
291
|
-
\
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
\
|
|
296
|
-
|
|
297
|
-
|
|
290
|
+
\ You're ready to automate iOS & Android code signing.\n\n\e[35mTwo ways to use
|
|
291
|
+
it:\e[0m\n • \e[1mWith a free My Signer account\e[0m (keys stored & synced for
|
|
292
|
+
you):\n \e[33mRun\e[0m \e[1m`mysigner onboard`\e[0m\n • \e[1mNo account —
|
|
293
|
+
your keys stay on this machine\e[0m (nothing sent to a server):\n \e[33mRun\e[0m
|
|
294
|
+
\e[1m`mysigner --local-only onboard`\e[0m\n \e[33mNot sure? Start with --local-only.\e[0m\n\n\e[35mAlso
|
|
295
|
+
handy:\e[0m\n • \e[33mRun\e[0m \e[1m`mysigner doctor`\e[0m – Check your dev environment
|
|
296
|
+
(JDK, SDK, Xcode…)\n • \e[33mRun\e[0m \e[1m`mysigner help`\e[0m – Explore every
|
|
297
|
+
command\n\n\e[35miOS (needs a Mac):\e[0m mysigner ship testflight\n\e[35mAndroid:\e[0m
|
|
298
|
+
\ mysigner ship internal --platform android\n\n\e[36mDocs:\e[0m https://mysigner.dev/docs/commands\n"
|
|
298
299
|
rdoc_options: []
|
|
299
300
|
require_paths:
|
|
300
301
|
- lib
|
|
@@ -309,7 +310,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
309
310
|
- !ruby/object:Gem::Version
|
|
310
311
|
version: '0'
|
|
311
312
|
requirements: []
|
|
312
|
-
rubygems_version:
|
|
313
|
+
rubygems_version: 3.6.9
|
|
313
314
|
specification_version: 4
|
|
314
315
|
summary: CLI tool for iOS and Android code signing automation via My Signer API
|
|
315
316
|
test_files: []
|