mysigner 0.3.0 → 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 +31 -0
- data/Gemfile.lock +2 -2
- data/README.md +18 -1
- 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 +110 -7
- 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 +79 -27
- data/lib/mysigner/cli/validate_commands.rb +16 -1
- data/lib/mysigner/config.rb +23 -3
- 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
|
|
@@ -1421,6 +1423,13 @@ module Mysigner
|
|
|
1421
1423
|
DESC
|
|
1422
1424
|
method_option :name, type: :string, desc: 'Display name for the app'
|
|
1423
1425
|
def android(action, *args)
|
|
1426
|
+
# mysigner-22 follow-up — `android build` is the only LOCAL action;
|
|
1427
|
+
# init/add/list all manage MySigner-registered records. Gate the
|
|
1428
|
+
# rest at the dispatcher top so users see "android add" in the
|
|
1429
|
+
# banner (not the underlying "apps" call that `list` invokes) and
|
|
1430
|
+
# so `android add` doesn't crash with NoMethodError on the nil
|
|
1431
|
+
# client further down.
|
|
1432
|
+
exit_unless_local_supported!("android #{action}") unless %w[build help].include?(action)
|
|
1424
1433
|
config = load_config
|
|
1425
1434
|
client = create_client(config)
|
|
1426
1435
|
|
|
@@ -1724,8 +1733,12 @@ module Mysigner
|
|
|
1724
1733
|
if keystore_info
|
|
1725
1734
|
say "🔐 Keystore: #{keystore_info[:name]}", :green
|
|
1726
1735
|
else
|
|
1727
|
-
say '⚠️ No keystore configured
|
|
1728
|
-
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
|
|
1729
1742
|
end
|
|
1730
1743
|
say ''
|
|
1731
1744
|
say '⏱️ This may take a few minutes...', :yellow
|
|
@@ -1771,16 +1784,21 @@ module Mysigner
|
|
|
1771
1784
|
say ' mysigner ship internal --platform android', :green
|
|
1772
1785
|
say ''
|
|
1773
1786
|
|
|
1774
|
-
# Open the folder containing the AAB
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
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
|
|
1784
1802
|
end
|
|
1785
1803
|
rescue Build::Detector::NoProjectError => e
|
|
1786
1804
|
error e.message
|
|
@@ -1892,12 +1910,19 @@ module Mysigner
|
|
|
1892
1910
|
# Write modified app.json
|
|
1893
1911
|
File.write(app_json_path, JSON.pretty_generate(config))
|
|
1894
1912
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
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
|
|
1899
1923
|
|
|
1900
|
-
|
|
1924
|
+
begin
|
|
1925
|
+
# Regenerate the native android/ from the version-bumped config.
|
|
1901
1926
|
Dir.chdir(project_dir) do
|
|
1902
1927
|
success = system('npx', 'expo', 'prebuild', '--platform', 'android', '--clean')
|
|
1903
1928
|
raise 'expo prebuild failed' unless success
|
|
@@ -1912,8 +1937,28 @@ module Mysigner
|
|
|
1912
1937
|
File.expand_path('~/Library/Android/sdk')
|
|
1913
1938
|
File.write(local_props_path, "sdk.dir=#{sdk_path}\n") if Dir.exist?(sdk_path)
|
|
1914
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
|
|
1915
1960
|
ensure
|
|
1916
|
-
#
|
|
1961
|
+
# Always restore the original app.json
|
|
1917
1962
|
File.write(app_json_path, original_content)
|
|
1918
1963
|
end
|
|
1919
1964
|
end
|
|
@@ -2109,17 +2154,23 @@ module Mysigner
|
|
|
2109
2154
|
gradle_args = ['./gradlew', 'bundleRelease', '--warning-mode=all']
|
|
2110
2155
|
gradle_args << "-PversionCode=#{version_code_override}" if version_code_override
|
|
2111
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).
|
|
2112
2160
|
injector = nil
|
|
2113
2161
|
env = {}
|
|
2114
|
-
if keystore_info
|
|
2162
|
+
if keystore_info || version_code_override
|
|
2115
2163
|
injector = Mysigner::Signing::GradleSigningInjector.new
|
|
2116
2164
|
init_path = injector.write_init_script!
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
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
|
|
2123
2174
|
gradle_args.insert(1, '--init-script', init_path)
|
|
2124
2175
|
end
|
|
2125
2176
|
|
|
@@ -2138,9 +2189,10 @@ module Mysigner
|
|
|
2138
2189
|
# Find the AAB
|
|
2139
2190
|
aab_path = File.join(android_dir, 'app/build/outputs/bundle/release/app-release.aab')
|
|
2140
2191
|
unless File.exist?(aab_path)
|
|
2141
|
-
#
|
|
2192
|
+
# Fall back to the NEWEST matching AAB so a stale/wrong-flavor
|
|
2193
|
+
# artifact from a previous build is never returned.
|
|
2142
2194
|
alt_paths = Dir.glob(File.join(android_dir, 'app/build/outputs/bundle/*/*.aab'))
|
|
2143
|
-
aab_path = alt_paths.
|
|
2195
|
+
aab_path = alt_paths.max_by { |f| File.mtime(f) } if alt_paths.any?
|
|
2144
2196
|
end
|
|
2145
2197
|
aab_path
|
|
2146
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
|
@@ -72,7 +72,15 @@ module Mysigner
|
|
|
72
72
|
# Local-only mode at the Config level: cascade ENV → file. The CLI
|
|
73
73
|
# Helpers concern layers --local-only / --no-local-only on top.
|
|
74
74
|
def self.local_only?
|
|
75
|
-
|
|
75
|
+
local_only_from_env? || local_only_from_file?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Public predicate for the env-var source. Mirrors local_only_from_file?
|
|
79
|
+
# so status's "Source: …" attribution can distinguish env vs file
|
|
80
|
+
# using the same truthy parser the cascade uses (a literal env value
|
|
81
|
+
# of "0" / "false" reads as off, not as "env var enabled it").
|
|
82
|
+
def self.local_only_from_env?
|
|
83
|
+
truthy_env?(ENV_LOCAL_ONLY)
|
|
76
84
|
end
|
|
77
85
|
|
|
78
86
|
# Lightweight check that reads only ~/.mysigner/config.yml's
|
|
@@ -243,13 +251,25 @@ module Mysigner
|
|
|
243
251
|
# Display config (with masked tokens)
|
|
244
252
|
def display
|
|
245
253
|
current_org_name = org_name(@current_organization_id) || '(not set)'
|
|
246
|
-
|
|
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
|
|
247
267
|
|
|
248
268
|
display_data = {
|
|
249
269
|
api_url: @api_url || '(not set)',
|
|
250
270
|
user_email: @user_email || '(not set)',
|
|
251
271
|
current_organization: "#{current_org_name} (ID: #{@current_organization_id || 'not set'})",
|
|
252
|
-
current_token:
|
|
272
|
+
current_token: token_display
|
|
253
273
|
}
|
|
254
274
|
|
|
255
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: []
|