fastlane-plugin-apprepo 0.1.0 → 0.2.0
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/.coveralls.yml +2 -0
- data/.gitignore +0 -0
- data/.rspec +3 -0
- data/.rubocop.yml +4 -0
- data/Gemfile +7 -1
- data/README.md +9 -2
- data/assets/RepofileDefault +34 -0
- data/assets/apprepo.png +0 -0
- data/assets/circle.key +27 -0
- data/assets/fastlane.png +0 -0
- data/assets/manifest.png +0 -0
- data/circle.yml +11 -9
- data/coverage/.last_run.json +5 -0
- data/coverage/.resultset.json +1244 -0
- data/coverage/.resultset.json.lock +0 -0
- data/fastlane-plugin-apprepo.gemspec +6 -2
- data/fastlane/Appfile +1 -0
- data/fastlane/Fastfile +42 -0
- data/fastlane/Pluginfile +1 -0
- data/fastlane/Repofile +33 -0
- data/greeter.rb +6 -0
- data/lib/fastlane/plugin/apprepo.rb +26 -7
- data/lib/fastlane/plugin/apprepo/actions/apprepo_action.rb +106 -92
- data/lib/fastlane/plugin/apprepo/actions/download_manifest.rb +40 -0
- data/lib/fastlane/plugin/apprepo/actions/init.rb +46 -0
- data/lib/fastlane/plugin/apprepo/actions/rubocop.rb +29 -0
- data/lib/fastlane/plugin/apprepo/actions/run.rb +69 -0
- data/lib/fastlane/plugin/apprepo/actions/submit.rb +41 -0
- data/lib/fastlane/plugin/apprepo/analyser.rb +35 -0
- data/lib/fastlane/plugin/apprepo/command.rb +17 -0
- data/lib/fastlane/plugin/apprepo/commands_generator.rb +121 -0
- data/lib/fastlane/plugin/apprepo/detect_values.rb +29 -0
- data/lib/fastlane/plugin/apprepo/helper/analyser.rb +35 -0
- data/lib/fastlane/plugin/apprepo/helper/commands_generator.rb +121 -0
- data/lib/fastlane/plugin/apprepo/helper/detect_values.rb +29 -0
- data/lib/fastlane/plugin/apprepo/helper/loader.rb +15 -0
- data/lib/fastlane/plugin/apprepo/helper/manifest.rb +44 -0
- data/lib/fastlane/plugin/apprepo/helper/options.rb +120 -0
- data/lib/fastlane/plugin/apprepo/helper/runner.rb +68 -0
- data/lib/fastlane/plugin/apprepo/helper/setup.rb +49 -0
- data/lib/fastlane/plugin/apprepo/helper/uploader.rb +301 -0
- data/lib/fastlane/plugin/apprepo/loader.rb +15 -0
- data/lib/fastlane/plugin/apprepo/manifest.rb +44 -0
- data/lib/fastlane/plugin/apprepo/options.rb +120 -0
- data/lib/fastlane/plugin/apprepo/runner.rb +68 -0
- data/lib/fastlane/plugin/apprepo/setup.rb +49 -0
- data/lib/fastlane/plugin/apprepo/uploader.rb +301 -0
- data/lib/fastlane/plugin/apprepo/version.rb +4 -3
- data/manifest.json +10 -0
- data/sampleapp.ipa +1 -0
- data/test +0 -0
- metadata +46 -2
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fastlane_core/languages'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Apprepo
|
5
|
+
# Responsible for loading language folders
|
6
|
+
module Loader
|
7
|
+
def self.language_folders(root)
|
8
|
+
Dir.glob(File.join(root, '*')).select do |path|
|
9
|
+
all = ALL_LANGUAGES.include?(File.basename(path).downcase)
|
10
|
+
File.directory?(path) && all
|
11
|
+
end.sort
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Apprepo
|
5
|
+
# Responsible for parsing and providing manifest.json
|
6
|
+
class Manifest
|
7
|
+
#
|
8
|
+
# Translated internal key names from Fastlane to Apprepo
|
9
|
+
#
|
10
|
+
|
11
|
+
attr_accessor :appcode # Apprepo Internal Code
|
12
|
+
attr_accessor :filename # IPA file name
|
13
|
+
attr_accessor :bundle_identifier # app_identifier
|
14
|
+
attr_accessor :bundle_version # app_version
|
15
|
+
attr_accessor :title # app_name
|
16
|
+
attr_accessor :subtitle # app_description
|
17
|
+
attr_accessor :notify # will send push notification / slack
|
18
|
+
|
19
|
+
def initialize(appcode)
|
20
|
+
self.appcode = appcode
|
21
|
+
UI.message('Initializing requires APPCODE. ' + self.appcode)
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_json(json)
|
25
|
+
# TODO: load values from JSON
|
26
|
+
end
|
27
|
+
|
28
|
+
# Provide JSON serialized data
|
29
|
+
def manifest_as_json
|
30
|
+
structure = {
|
31
|
+
appcode: appcode,
|
32
|
+
filename: filename,
|
33
|
+
bundle_identifier: bundle_identifier,
|
34
|
+
bundle_version: bundle_version,
|
35
|
+
title: title,
|
36
|
+
subtitle: subtitle,
|
37
|
+
notify: notify
|
38
|
+
}
|
39
|
+
|
40
|
+
fputs structure
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'fastlane_core'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Apprepo
|
5
|
+
# Provides available options for the commands generator
|
6
|
+
class Options
|
7
|
+
# rubocop:disable Metrics/AbcSize
|
8
|
+
def self.available_options
|
9
|
+
[
|
10
|
+
FastlaneCore::ConfigItem.new(key: :ipa,
|
11
|
+
short_option: '-i',
|
12
|
+
optional: true,
|
13
|
+
env_name: 'Apprepo_IPA_PATH',
|
14
|
+
description: 'Path to your ipa file',
|
15
|
+
default_value: Dir['*.ipa'].first,
|
16
|
+
verify_block: proc do |value|
|
17
|
+
UI.user_error!("Could not find ipa file at path '#{value}'") unless File.exist?(value)
|
18
|
+
UI.user_error!("'#{value}' doesn't seem to be an ipa file") unless value.end_with?('.ipa')
|
19
|
+
end),
|
20
|
+
FastlaneCore::ConfigItem.new(key: :app_identifier,
|
21
|
+
short_option: '-b',
|
22
|
+
optional: false,
|
23
|
+
env_name: 'Apprepo_APP_ID',
|
24
|
+
description: 'Your bundle identifier',
|
25
|
+
default_value: ''),
|
26
|
+
FastlaneCore::ConfigItem.new(key: :app_code,
|
27
|
+
short_option: '-c',
|
28
|
+
optional: true,
|
29
|
+
env_name: 'Apprepo_APPCODE',
|
30
|
+
description: 'APPCODE value for Apprepo'),
|
31
|
+
FastlaneCore::ConfigItem.new(key: :repo_url,
|
32
|
+
short_option: '-r',
|
33
|
+
optional: false,
|
34
|
+
env_name: 'Apprepo_URL',
|
35
|
+
description: 'URL of your Apprepo server'),
|
36
|
+
FastlaneCore::ConfigItem.new(key: :repo_user,
|
37
|
+
short_option: '-u',
|
38
|
+
optional: false,
|
39
|
+
env_name: 'Apprepo_USER',
|
40
|
+
description: 'USER of your Apprepo server'),
|
41
|
+
FastlaneCore::ConfigItem.new(key: :repo_password,
|
42
|
+
short_option: '-p',
|
43
|
+
optional: true,
|
44
|
+
env_name: 'Apprepo_PASSWORD',
|
45
|
+
description: 'PASSWORD for your Apprepo server (not for production)',
|
46
|
+
conflicting_options: [:repo_key],
|
47
|
+
conflict_block: proc do |value|
|
48
|
+
UI.user_error!("You can't use 'password' and '#{value.key}' options in one run.")
|
49
|
+
end),
|
50
|
+
FastlaneCore::ConfigItem.new(key: :repo_key,
|
51
|
+
short_option: '-k',
|
52
|
+
optional: false,
|
53
|
+
env_name: 'Apprepo_KEY',
|
54
|
+
description: 'RSA key for your Apprepo server',
|
55
|
+
conflicting_options: [:repo_password],
|
56
|
+
conflict_block: proc do |value|
|
57
|
+
UI.user_error!("You can't use 'repo_key' and '#{value.key}' options in one run.")
|
58
|
+
end),
|
59
|
+
FastlaneCore::ConfigItem.new(key: :repo_description,
|
60
|
+
short_option: '-d',
|
61
|
+
optional: true,
|
62
|
+
description: 'Long detailed description for your Apprepo server',
|
63
|
+
default_value: ''),
|
64
|
+
FastlaneCore::ConfigItem.new(key: :repo_summary,
|
65
|
+
short_option: '-s',
|
66
|
+
optional: true,
|
67
|
+
description: 'Short description for your Apprepo server',
|
68
|
+
default_value: ''),
|
69
|
+
FastlaneCore::ConfigItem.new(key: :manifest_path,
|
70
|
+
short_option: '-m',
|
71
|
+
description: 'Path to the folder containing the metadata files',
|
72
|
+
optional: true),
|
73
|
+
FastlaneCore::ConfigItem.new(key: :repo_title,
|
74
|
+
short_option: '-a',
|
75
|
+
description: 'Title of the app',
|
76
|
+
optional: false),
|
77
|
+
FastlaneCore::ConfigItem.new(key: :appcode,
|
78
|
+
short_option: '-o',
|
79
|
+
description: 'Name of the app on Apprepo',
|
80
|
+
optional: false),
|
81
|
+
FastlaneCore::ConfigItem.new(key: :skip_binary_upload,
|
82
|
+
description: 'Skip uploading an ipa or to Apprepo',
|
83
|
+
is_string: false,
|
84
|
+
default_value: false),
|
85
|
+
FastlaneCore::ConfigItem.new(key: :app_version,
|
86
|
+
short_option: '-z',
|
87
|
+
description: 'The version that should be edited or created',
|
88
|
+
optional: true),
|
89
|
+
FastlaneCore::ConfigItem.new(key: :skip_manifest,
|
90
|
+
description: "Don't upload the metadata (e.g. title, description), this will still upload screenshots",
|
91
|
+
is_string: false,
|
92
|
+
default_value: false),
|
93
|
+
FastlaneCore::ConfigItem.new(key: :notify,
|
94
|
+
description: 'Notify Apprepo users on update',
|
95
|
+
is_string: false,
|
96
|
+
default_value: false),
|
97
|
+
FastlaneCore::ConfigItem.new(key: :build_number,
|
98
|
+
short_option: '-n',
|
99
|
+
description: 'If set the given build number (already uploaded to iTC) will be used instead of the current built one',
|
100
|
+
optional: true,
|
101
|
+
conflicting_options: [:ipa],
|
102
|
+
conflict_block: proc do |value|
|
103
|
+
UI.user_error!("You can't use 'build_number' and '#{value.key}' options in one run.")
|
104
|
+
end),
|
105
|
+
|
106
|
+
# App Metadata
|
107
|
+
# Non Localised
|
108
|
+
FastlaneCore::ConfigItem.new(key: :app_icon,
|
109
|
+
description: 'Metadata: The path to the app icon',
|
110
|
+
optional: true,
|
111
|
+
short_option: '-l',
|
112
|
+
verify_block: proc do |value|
|
113
|
+
UI.user_error!("Could not find png file at path '#{value}'") unless File.exist?(value)
|
114
|
+
UI.user_error!("'#{value}' doesn't seem to be a png file") unless value.end_with?('.png')
|
115
|
+
end)
|
116
|
+
]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative 'uploader'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Apprepo
|
5
|
+
# Responsible for running
|
6
|
+
class Runner
|
7
|
+
attr_accessor :options
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
self.options = options
|
11
|
+
Apprepo::DetectValues.new.run!(self.options)
|
12
|
+
FastlaneCore::PrintTable.print_values(config: options, hide_keys: [:repo_password], mask_keys: [:repo_key], title: "Apprepo-sftp #{Apprepo::VERSION} Summary")
|
13
|
+
end
|
14
|
+
|
15
|
+
# rubocop:disable Metrics/AbcSize
|
16
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
17
|
+
def run
|
18
|
+
UI.success('Apprepo SFTP Uploader running...')
|
19
|
+
verify_version unless options[:app_version].to_s.empty?
|
20
|
+
has_binary = options[:ipa]
|
21
|
+
if !options[:skip_binary_upload] && !options[:build_number] && has_binary
|
22
|
+
upload_binary
|
23
|
+
end
|
24
|
+
UI.success('Finished the upload to Apprepo.')
|
25
|
+
notify unless options[:notify].nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Make sure the version on Apprepo matches the one in the ipa
|
29
|
+
# If not, the new version will automatically be created
|
30
|
+
def verify_version
|
31
|
+
app_version = options[:app_version]
|
32
|
+
msg = "TODO: Test if Apprepo matches '#{app_version}' from the IPA..."
|
33
|
+
UI.message(msg)
|
34
|
+
|
35
|
+
# changed = options[:app].ensure_version!(app_version)
|
36
|
+
# if changed
|
37
|
+
# UI.success("Successfully set the version to '#{app_version}'")
|
38
|
+
# else
|
39
|
+
# UI.success("'#{app_version}' is the latest version on Apprepo")
|
40
|
+
# end
|
41
|
+
end
|
42
|
+
|
43
|
+
def download_manifest
|
44
|
+
if options[:manifest_path]
|
45
|
+
uploader = Apprepo::Uploader.new(options)
|
46
|
+
result = uploader.download_manifest_only
|
47
|
+
msg = 'Metadata download failed. Check out the error above.'
|
48
|
+
UI.user_error!(msg) unless result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Upload the binary to Apprepo
|
53
|
+
def upload_binary
|
54
|
+
if options[:ipa]
|
55
|
+
uploader = Apprepo::Uploader.new(options)
|
56
|
+
result = uploader.upload
|
57
|
+
msg = 'Binary upload failed. Check out the error above.'
|
58
|
+
UI.user_error!(msg) unless result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def notify
|
63
|
+
# should be in metadata
|
64
|
+
UI.command_output('TODO: Missing implementation for Apprepo Push Notifier')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Apprepo
|
3
|
+
# Responsible for setting up the Repofile configuration
|
4
|
+
class Setup
|
5
|
+
def setup_Apprepo(file_path, data, _Apprepo_path, _options)
|
6
|
+
UI.message('[Apprepo:Setup] Setting up...')
|
7
|
+
File.write(file_path, data)
|
8
|
+
|
9
|
+
# TODO: implement later
|
10
|
+
download_manifest(Apprepo_path, options)
|
11
|
+
|
12
|
+
UI.success("NOT! created new Repofile at path '#{file_path}'")
|
13
|
+
end
|
14
|
+
|
15
|
+
# This method takes care of creating a new 'Apprepo' folder with metadata
|
16
|
+
# and screenshots folders
|
17
|
+
def generate_Apprepo_file(_Apprepo_path, options)
|
18
|
+
# v = options[:app].latest_version
|
19
|
+
# generate_Apprepo_file(v, File.join(Apprepo_path, 'manifest.json'))
|
20
|
+
|
21
|
+
# Generate the final Repofile here
|
22
|
+
gem_path = Helper.gem_path('Apprepo')
|
23
|
+
Apprepo = File.read("#{gem_path}/../assets/RepofileDefault")
|
24
|
+
Apprepo.gsub!('[[APP_IDENTIFIER]]', options[:app].bundle_id)
|
25
|
+
Apprepo.gsub!('[[Apprepo_IPA_PATH]]', options[:app].file_path)
|
26
|
+
Apprepo.gsub!('[[APP_VERSION]]', options[:app].version)
|
27
|
+
Apprepo.gsub!('[[APP_NAME]]', options[:app].name)
|
28
|
+
# Apprepo (was deliver)
|
29
|
+
end
|
30
|
+
|
31
|
+
def download_manifest(Apprepo_path, _options)
|
32
|
+
path = File.join(Apprepo_path, 'metadata')
|
33
|
+
FileUtils.mkdir_p(path)
|
34
|
+
UI.success("TODO: DOWNLOAD MANIFEST'")
|
35
|
+
Apprepo::Uploader.new(options).download_manifest_only
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(options)
|
39
|
+
UI.message('[Apprepo:Setup] Running...')
|
40
|
+
containing = (File.directory?('fastlane') ? 'fastlane' : '.')
|
41
|
+
file_path = File.join(containing, 'Repofile')
|
42
|
+
data = generate_Apprepo_file(containing, options)
|
43
|
+
setup_Apprepo(file_path, data, containing, options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @setup = new Apprepo::Setup
|
49
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'json'
|
5
|
+
require 'net/ssh'
|
6
|
+
require 'net/sftp'
|
7
|
+
require 'fastlane_core'
|
8
|
+
require 'fastlane_core/languages'
|
9
|
+
|
10
|
+
require_relative 'options'
|
11
|
+
|
12
|
+
module Fastlane
|
13
|
+
module Apprepo
|
14
|
+
# rubocop:disable Metrics/ClassLength
|
15
|
+
|
16
|
+
# Responsible for performing the SFTP operation
|
17
|
+
class Uploader
|
18
|
+
attr_accessor :options
|
19
|
+
|
20
|
+
#
|
21
|
+
# These want to be an input parameters:
|
22
|
+
#
|
23
|
+
|
24
|
+
attr_accessor :host
|
25
|
+
attr_accessor :user
|
26
|
+
attr_accessor :password
|
27
|
+
attr_accessor :rsa_keypath
|
28
|
+
attr_accessor :ipa_path
|
29
|
+
attr_accessor :manifest_path
|
30
|
+
attr_accessor :appcode
|
31
|
+
|
32
|
+
# rubocop:disable Metrics/AbcSize
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
34
|
+
def initialize(options)
|
35
|
+
self.options = options unless options.nil?
|
36
|
+
self.host = options[:repo_url] # 'repo.teacloud.net'
|
37
|
+
self.user = options[:repo_user]
|
38
|
+
self.password = options[:repo_password]
|
39
|
+
self.rsa_keypath = options[:repo_key] # '../assets/circle.key'
|
40
|
+
self.ipa_path = options[:ipa] # '../sampleapp.ipa'
|
41
|
+
self.manifest_path = options[:manifest_path] # '../assets/example_manifest.json'
|
42
|
+
self.appcode = options[:appcode]
|
43
|
+
|
44
|
+
# Apprepo::Uploader.new.run!
|
45
|
+
# FastlaneCore::PrintTable.print_values(config: nil , hide_keys: [:app],
|
46
|
+
# mask_keys: ['app_review_information.demo_password'],
|
47
|
+
# title: "deliver #{Apprepo::VERSION} Summary") # options
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Upload IPA & manifest
|
52
|
+
#
|
53
|
+
|
54
|
+
# rubocop:disable Metrics/AbcSize
|
55
|
+
# rubocop:disable Metrics/MethodLength
|
56
|
+
def upload
|
57
|
+
# Login & Upload IPA with metadata using RSA key or username/password
|
58
|
+
FastlaneCore::UI.message('upload...')
|
59
|
+
|
60
|
+
if host.nil? || user.nil?
|
61
|
+
FastlaneCore::UI.user_error('repo_url, repo_user and repo_pasdword or repo_key must be set on upload')
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
if rsa_keypath
|
66
|
+
rsa_key = load_rsa_key(rsa_keypath)
|
67
|
+
if rsa_key.nil?
|
68
|
+
FastlaneCore::UI.user_error('Failed to load RSA key... ' + options[:rsa_keypath])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
success = false
|
73
|
+
if !rsa_key.nil?
|
74
|
+
FastlaneCore::UI.message('Logging in with RSA key...')
|
75
|
+
Net::SSH.start(host, user, key_data: rsa_key, keys_only: true) do |ssh|
|
76
|
+
FastlaneCore::UI.message('Uploading IPA & Manifest...')
|
77
|
+
success = ssh_sftp_upload(ssh, ipa_path, manifest_path)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
FastlaneCore::UI.message('Logging in with username/password...')
|
81
|
+
Net::SSH.start(host, user, password: password) do |ssh|
|
82
|
+
FastlaneCore::UI.message('Uploading IPA & Manifest...')
|
83
|
+
success = ssh_sftp_upload(ssh, ipa_path, manifest_path)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
success
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Download metadata only
|
91
|
+
#
|
92
|
+
|
93
|
+
# rubocop:disable Metrics/AbcSize
|
94
|
+
# rubocop:disable Metrics/MethodLength
|
95
|
+
def download_manifest_only
|
96
|
+
FastlaneCore::UI.message('download_manifest_only...')
|
97
|
+
rsa_key = load_rsa_key(rsa_keypath)
|
98
|
+
success = true
|
99
|
+
if !rsa_key.nil?
|
100
|
+
FastlaneCore::UI.message('Logging in with RSA key for download...')
|
101
|
+
Net::SSH.start(host, user, key_data: rsa_key, keys_only: true) do |ssh|
|
102
|
+
FastlaneCore::UI.message('Uploading UPA & Manifest...')
|
103
|
+
success = ssh_sftp_download(ssh, manifest_path)
|
104
|
+
end
|
105
|
+
else
|
106
|
+
FastlaneCore::UI.message('Logging in for download...')
|
107
|
+
Net::SSH.start(host, user, password: password) do |ssh|
|
108
|
+
FastlaneCore::UI.message('Uploading UPA & Manifest...')
|
109
|
+
success = ssh_sftp_download(ssh, manifest_path)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
success
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def ssh_sftp_download(ssh, _manifest_path)
|
118
|
+
ssh.sftp.connect do |sftp|
|
119
|
+
FastlaneCore::UI.message('Fetching remote manifest...')
|
120
|
+
manifest = download_manifest(sftp)
|
121
|
+
puts '********************************************************'
|
122
|
+
puts JSON.pretty_generate(manifest)
|
123
|
+
puts '********************************************************'
|
124
|
+
FastlaneCore::UI.success('Successfully fetched manifest')
|
125
|
+
FastlaneCore::UI.command_output('TODO: Processing manifest not implemented.')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def ssh_sftp_upload(ssh, local_ipa_path, manifest_path)
|
130
|
+
ssh.sftp.connect do |sftp|
|
131
|
+
break unless check_ipa(local_ipa_path)
|
132
|
+
check_appcode(sftp, appcode)
|
133
|
+
path = remote_path(appcode)
|
134
|
+
manifest = download_manifest(sftp)
|
135
|
+
puts JSON.pretty_generate(manifest) unless manifest.nil?
|
136
|
+
bump_ipa(sftp, local_ipa_path, appcode)
|
137
|
+
remote_ipa_path = get_remote_ipa_path(local_ipa_path, appcode)
|
138
|
+
upload_ipa(sftp, local_ipa_path, remote_ipa_path)
|
139
|
+
upload_manifest(sftp, manifest_path, remote_manifest_path(appcode))
|
140
|
+
# Lists the entries in a directory for verification
|
141
|
+
sftp.dir.foreach(path) do |entry|
|
142
|
+
FastlaneCore::UI.message(entry.longname)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Check IPA existence locally
|
148
|
+
#
|
149
|
+
# @param local_ipa_path
|
150
|
+
def check_ipa(local_ipa_path)
|
151
|
+
if File.exist?(local_ipa_path)
|
152
|
+
FastlaneCore::UI.important('IPA found at ' + local_ipa_path)
|
153
|
+
return true
|
154
|
+
else
|
155
|
+
FastlaneCore::UI.verbose('IPA at given path does not exist yet.')
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Private methods - Remote Operations
|
161
|
+
|
162
|
+
# Checks/creates remote APPCODE directory
|
163
|
+
# @param sftp
|
164
|
+
# @param [String] appcode
|
165
|
+
def check_appcode(sftp, appcode)
|
166
|
+
path = remote_path(appcode)
|
167
|
+
FastlaneCore::UI.message('Checking APPCODE')
|
168
|
+
remote_mkdir(sftp, path)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Checks/renames remote IPA
|
172
|
+
#
|
173
|
+
# @params sftp
|
174
|
+
# @params [String] local_ipa_path
|
175
|
+
def bump_ipa(sftp, local, appcode)
|
176
|
+
remote = get_remote_ipa_path(local, appcode)
|
177
|
+
FastlaneCore::UI.message('Checking remote IPA')
|
178
|
+
begin
|
179
|
+
sftp.stat!(remote) do |response|
|
180
|
+
if response.ok?
|
181
|
+
begin
|
182
|
+
sftp.rename!(remote, remote + '.bak')
|
183
|
+
rescue
|
184
|
+
begin
|
185
|
+
sftp.remove(remote + '.bak') # may fail if not existent
|
186
|
+
FastlaneCore::UI.message('Removed ' + remote + '.bak')
|
187
|
+
rescue
|
188
|
+
sftp.rename!(remote, remote + '.bak')
|
189
|
+
FastlaneCore::UI.message('Bumped to ' + remote + '.bak')
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
rescue
|
195
|
+
FastlaneCore::UI.message('No previous IPA found.')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Downloads remote manifest, self.appcode required by options.
|
200
|
+
#
|
201
|
+
# @param sftp
|
202
|
+
# @param [String] remote_path
|
203
|
+
# @returns [JSON] json or nil
|
204
|
+
def download_manifest(sftp)
|
205
|
+
FastlaneCore::UI.message('Checking remote Manifest')
|
206
|
+
json = nil
|
207
|
+
remote_manifest_path = remote_manifest_path(appcode)
|
208
|
+
begin
|
209
|
+
sftp.stat!(remote_manifest_path) do |response|
|
210
|
+
if response.ok?
|
211
|
+
FastlaneCore::UI.success('Loading remote manifest:')
|
212
|
+
manifest = sftp.download!(remote_manifest_path)
|
213
|
+
json = JSON.parse(manifest)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
rescue
|
217
|
+
FastlaneCore::UI.message('No previous Manifest found')
|
218
|
+
end
|
219
|
+
json
|
220
|
+
end
|
221
|
+
|
222
|
+
# Upload current IPA
|
223
|
+
#
|
224
|
+
# @param sftp
|
225
|
+
# @param [String] local_ipa_path
|
226
|
+
# @param [String] remote_ipa_path
|
227
|
+
def upload_ipa(sftp, local_ipa_path, remote_ipa_path)
|
228
|
+
msg = "[Uploading IPA] #{local_ipa_path} to #{remote_ipa_path}"
|
229
|
+
FastlaneCore::UI.message(msg)
|
230
|
+
result = sftp.upload!(local_ipa_path, remote_ipa_path) do |event, _uploader, *_args|
|
231
|
+
case event
|
232
|
+
when :open then
|
233
|
+
putc '.'
|
234
|
+
when :put then
|
235
|
+
putc '.'
|
236
|
+
$stdout.flush
|
237
|
+
when :close then
|
238
|
+
puts "\n"
|
239
|
+
when :finish then
|
240
|
+
FastlaneCore::UI.success('IPA upload successful')
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Upload current manifest.json
|
246
|
+
#
|
247
|
+
# @param sftp
|
248
|
+
# @param [String] manifest_path
|
249
|
+
# @param [String] remote_manifest_path
|
250
|
+
def upload_manifest(sftp, local_path, remote_path)
|
251
|
+
msg = '[Uploading Manifest] ' + local_path + ' to ' + remote_path
|
252
|
+
FastlaneCore::UI.message(msg)
|
253
|
+
result = sftp.upload!(local_path, remote_path) do |event, _uploader, *_args|
|
254
|
+
case event
|
255
|
+
when :finish then
|
256
|
+
FastlaneCore::UI.success('Manifest upload successful')
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def get_remote_ipa_path(local_ipa_path, appcode)
|
262
|
+
remote_path(appcode) + File.basename(local_ipa_path)
|
263
|
+
end
|
264
|
+
|
265
|
+
def remote_path(appcode)
|
266
|
+
generate_remote_path + appcode + '/'
|
267
|
+
end
|
268
|
+
|
269
|
+
def remote_manifest_path(appcode)
|
270
|
+
remote_manifest_path = remote_path(appcode) + 'manifest.json'
|
271
|
+
end
|
272
|
+
|
273
|
+
def generate_remote_path
|
274
|
+
'/home/' + user + '/repo/apps/'
|
275
|
+
end
|
276
|
+
|
277
|
+
def remote_mkdir(sftp, remote_path)
|
278
|
+
sftp.mkdir remote_path
|
279
|
+
rescue Net::SFTP::StatusException => e
|
280
|
+
raise if e.code != 11
|
281
|
+
msg = "Remote dir #{remote_path} exists."
|
282
|
+
FastlaneCore::UI.message(msg)
|
283
|
+
end
|
284
|
+
|
285
|
+
# Private methods - Local Operations
|
286
|
+
|
287
|
+
def load_rsa_key(rsa_keypath)
|
288
|
+
File.open(rsa_keypath, 'r') do |file|
|
289
|
+
rsa_key = nil
|
290
|
+
rsa_key = [file.read]
|
291
|
+
if !rsa_key.nil?
|
292
|
+
FastlaneCore::UI.success('Successfully loaded RSA key...')
|
293
|
+
else
|
294
|
+
FastlaneCore::UI.user_error!('Failed to load RSA key...')
|
295
|
+
end
|
296
|
+
rsa_key
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|