fastlane-plugin-sftp 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +94 -0
- data/lib/fastlane/plugin/sftp.rb +21 -0
- data/lib/fastlane/plugin/sftp/actions/sftp_download.rb +46 -0
- data/lib/fastlane/plugin/sftp/actions/sftp_upload.rb +46 -0
- data/lib/fastlane/plugin/sftp/helper/downloader.rb +123 -0
- data/lib/fastlane/plugin/sftp/helper/options.rb +82 -0
- data/lib/fastlane/plugin/sftp/helper/sftp_helper.rb +82 -0
- data/lib/fastlane/plugin/sftp/helper/uploader.rb +114 -0
- data/lib/fastlane/plugin/sftp/version.rb +7 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 132fa1cd768f7e5c72dec60fc0d0e795c5efed26
|
4
|
+
data.tar.gz: 711d7aa6ea3e25807eb10fd23de489f930db21ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c5f7e5d52adca26d17d85203ca6cf1100ea1cd7f82fdfb2fec937921f334f4ce58f2cf08d06eb82d16fa85427d7f0e16f1059fcf29fc94b9fe29c760280a5f4
|
7
|
+
data.tar.gz: 95dde5e4e9c17a96dc413b25ad08b93e9ae68b6932734deabfb68292d8437dc44fba3dbb3ca1107d0103dfa41641bb955b82fa1ade8a00eed2c742b41adc953e
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Oliver Limberg <o.limberg@portrix.net>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# sftp plugin
|
2
|
+
|
3
|
+
[![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-sftp)
|
4
|
+
[![Gem](https://img.shields.io/gem/v/fastlane-plugin-sftp.svg?style=flat)](http://rubygems.org/gems/fastlane-plugin-sftp)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/suculent/fastlane-plugin-sftp/badge.svg?branch=master)](https://coveralls.io/github/suculent/fastlane-plugin-sftp?branch=master)
|
6
|
+
[![Build Status](https://travis-ci.org/oklimberg/fastlane-plugin-sftp.svg?branch=master)](https://travis-ci.org/oklimberg/fastlane-plugin-sftp)
|
7
|
+
[![Twitter: @oklimberg](https://img.shields.io/badge/contact-@oklimberg-blue.svg?style=flat)](https://twitter.com/oklimberg)
|
8
|
+
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/suculent/fastlane-plugin-apprepo/blob/master/LICENSE)
|
9
|
+
|
10
|
+
## Getting Started
|
11
|
+
|
12
|
+
This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-sftp`, add it to your project by running:
|
13
|
+
|
14
|
+
```bash
|
15
|
+
fastlane add_plugin sftp
|
16
|
+
```
|
17
|
+
|
18
|
+
## About sftp
|
19
|
+
|
20
|
+
This plugin provides two actions to either upload files to a SFTP server or to download them.
|
21
|
+
It is inspired by the plugin [apprepo](https://github.com/suculent/apprepo) by Matej Sychra.
|
22
|
+
Since the apprepo plugin did not provide the possibility to provide a password for the RSA key fie, I
|
23
|
+
decided to write this plugin
|
24
|
+
|
25
|
+
## Actions
|
26
|
+
|
27
|
+
### sftp_upload
|
28
|
+
|
29
|
+
This action can be used, to upload multiple files or even complete folders to a SFTP server.
|
30
|
+
You can eiter provide a password via `server_password` or specify the path to a key file via `server_key`. If your keyfile has a password set, you can specify this via `server_key_passphrase`.
|
31
|
+
|
32
|
+
``` ruby
|
33
|
+
sftp_upload(
|
34
|
+
server_url: "example.host.com",
|
35
|
+
server_user: "john_doe",
|
36
|
+
server_key: "#{Dir.home}/.ssh/id_rsa",
|
37
|
+
target_dir: "remote/path/on/server",
|
38
|
+
file_paths:["test_file_01.txt", "test_file_02.txt", "test_folder_01"],
|
39
|
+
)
|
40
|
+
```
|
41
|
+
|
42
|
+
When uploading a folder, the source folder and ists contents will be placed inside the target dir on the remote server.
|
43
|
+
|
44
|
+
### sftp_download
|
45
|
+
|
46
|
+
This action can be used to download files or folders from a remote server. The parameters are teh same as for `sftp_upload` but the `target_dir` parameter specifies a local folder where all filles should be stored and the `file_paths` parameter specifies the path to the files or folders which should be downloaded.
|
47
|
+
|
48
|
+
``` ruby
|
49
|
+
sftp_download(
|
50
|
+
server_url: "example.host.com",,
|
51
|
+
server_user: "john_doe",
|
52
|
+
server_password: "secret"
|
53
|
+
target_dir: "local/folder",
|
54
|
+
file_paths:["path/to/remote_file_01.txt","path/to/remote_folder"],
|
55
|
+
)
|
56
|
+
```
|
57
|
+
|
58
|
+
## Example
|
59
|
+
|
60
|
+
Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
|
61
|
+
|
62
|
+
## Run tests for this plugin
|
63
|
+
|
64
|
+
To run both the tests, and code style validation, run
|
65
|
+
|
66
|
+
```
|
67
|
+
rake
|
68
|
+
```
|
69
|
+
|
70
|
+
To automatically fix many of the styling issues, use
|
71
|
+
```
|
72
|
+
rubocop -a
|
73
|
+
```
|
74
|
+
|
75
|
+
## Issues and Feedback
|
76
|
+
|
77
|
+
For any other issues and feedback about this plugin, please submit it to this repository.
|
78
|
+
|
79
|
+
## Troubleshooting
|
80
|
+
|
81
|
+
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
82
|
+
|
83
|
+
## Using _fastlane_ Plugins
|
84
|
+
|
85
|
+
For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
|
86
|
+
|
87
|
+
## About _fastlane_
|
88
|
+
|
89
|
+
_fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
|
90
|
+
|
91
|
+
# License
|
92
|
+
This project is licensed under the terms of the MIT license. See the LICENSE file.
|
93
|
+
|
94
|
+
> This project and all fastlane tools are in no way affiliated with Apple Inc. This project is open source under the MIT license, which means you have full access to the source code and can modify it to fit your own needs. All fastlane tools run on your own computer or server, so your credentials or other sensitive information will never leave your own computer. You are responsible for how you use fastlane tools.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'fastlane/plugin/sftp/version'
|
2
|
+
|
3
|
+
require 'fastlane'
|
4
|
+
require 'fastlane_core'
|
5
|
+
|
6
|
+
# require_relative 'apprepo/version'
|
7
|
+
|
8
|
+
module Fastlane
|
9
|
+
module Sftp
|
10
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
11
|
+
def self.all_classes
|
12
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# By default we want to import all available actions and helpers
|
18
|
+
# A plugin can contain any number of actions and plugins
|
19
|
+
Fastlane::Sftp.all_classes.each do |current|
|
20
|
+
require current
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/options'
|
3
|
+
require_relative '../helper/downloader'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
module Actions
|
7
|
+
class SftpDownloadAction < Action
|
8
|
+
def self.run(params)
|
9
|
+
# sh 'bundle exec rubocop -D'
|
10
|
+
FastlaneCore::PrintTable.print_values(config: params, hide_keys: [:server_password], mask_keys: [:server_key, :server_key_passphrase], title: "SFTP Download #{Sftp::VERSION} Summary")
|
11
|
+
|
12
|
+
UI.success('SFTP Downloader running...')
|
13
|
+
downloader = Sftp::Downloader.new(params)
|
14
|
+
result = downloader.download
|
15
|
+
msg = 'Download failed. Check out the error above.'
|
16
|
+
UI.user_error!(msg) unless result
|
17
|
+
UI.success('Finished the download.')
|
18
|
+
end
|
19
|
+
|
20
|
+
#####################################################
|
21
|
+
# @!group Documentation
|
22
|
+
#####################################################
|
23
|
+
|
24
|
+
def self.description
|
25
|
+
'download files from a remote Server via SFTP'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.details
|
29
|
+
# Optional:
|
30
|
+
"TODO"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.available_options
|
34
|
+
Sftp::Options.available_options_download
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.authors
|
38
|
+
['oklimberg@gmail.com']
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.is_supported?(platform)
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/options'
|
3
|
+
require_relative '../helper/uploader'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
module Actions
|
7
|
+
class SftpUploadAction < Action
|
8
|
+
def self.run(params)
|
9
|
+
# sh 'bundle exec rubocop -D'
|
10
|
+
FastlaneCore::PrintTable.print_values(config: params, hide_keys: [:server_password], mask_keys: [:server_key, :server_key_passphrase], title: "SFTP Upload #{Sftp::VERSION} Summary")
|
11
|
+
|
12
|
+
UI.success('SFTP Uploader running...')
|
13
|
+
uploader = Sftp::Uploader.new(params)
|
14
|
+
result = uploader.upload
|
15
|
+
msg = 'Upload failed. Check out the error above.'
|
16
|
+
UI.user_error!(msg) unless result
|
17
|
+
UI.success('Finished the upload.')
|
18
|
+
end
|
19
|
+
|
20
|
+
#####################################################
|
21
|
+
# @!group Documentation
|
22
|
+
#####################################################
|
23
|
+
|
24
|
+
def self.description
|
25
|
+
'upload files to a remote Server via SFTP'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.details
|
29
|
+
# Optional:
|
30
|
+
"TODO"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.available_options
|
34
|
+
Sftp::Options.available_options_upload
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.authors
|
38
|
+
['oklimberg@gmail.com']
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.is_supported?(platform)
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/sftp'
|
4
|
+
require 'fastlane_core'
|
5
|
+
require 'fastlane_core/languages'
|
6
|
+
|
7
|
+
require_relative 'options'
|
8
|
+
|
9
|
+
module Fastlane
|
10
|
+
module Sftp
|
11
|
+
# Responsible for performing download SFTP operation
|
12
|
+
class Downloader
|
13
|
+
attr_accessor :options
|
14
|
+
|
15
|
+
#
|
16
|
+
# These want to be an input parameters:
|
17
|
+
#
|
18
|
+
|
19
|
+
attr_accessor :host
|
20
|
+
attr_accessor :user
|
21
|
+
attr_accessor :password
|
22
|
+
attr_accessor :rsa_keypath
|
23
|
+
attr_accessor :rsa_keypath_passphrase
|
24
|
+
attr_accessor :target_dir
|
25
|
+
attr_accessor :root_path
|
26
|
+
attr_accessor :files
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
self.options = options unless options.nil?
|
30
|
+
self.host = options[:server_url]
|
31
|
+
self.user = options[:server_user]
|
32
|
+
self.password = options[:server_password]
|
33
|
+
self.rsa_keypath = options[:server_key]
|
34
|
+
self.rsa_keypath_passphrase = options[:server_key_passphrase]
|
35
|
+
self.files = options[:file_paths]
|
36
|
+
self.target_dir = options[:target_dir]
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Download files
|
41
|
+
#
|
42
|
+
|
43
|
+
def download
|
44
|
+
# Login & Download all files using RSA key or username/password
|
45
|
+
UI.message('download...')
|
46
|
+
session = Helper::SftpHelper.login(host, user, password, rsa_keypath, rsa_keypath_passphrase)
|
47
|
+
if session.nil?
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
UI.message('Downloading files...')
|
51
|
+
|
52
|
+
session.sftp.connect do |sftp|
|
53
|
+
source_files = files.map { |entry| Helper::SftpHelper.generate_remote_path(user, entry) }
|
54
|
+
downloads = sftp_download(sftp, source_files, target_dir)
|
55
|
+
downloads.each(&:wait)
|
56
|
+
|
57
|
+
# Lists the entries in a directory for verification
|
58
|
+
Dir.entries(target_dir).each do |entry|
|
59
|
+
UI.message(entry)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
session.close
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def sftp_download(sftp, source_files, target_dir)
|
69
|
+
Dir.mkdir(target_dir) unless Dir.exist?(target_dir)
|
70
|
+
downloads = []
|
71
|
+
source_files.each do |source|
|
72
|
+
begin
|
73
|
+
attrs = sftp.stat!(source)
|
74
|
+
if attrs.directory?
|
75
|
+
children = []
|
76
|
+
sftp.dir.glob(source, "*") do |child|
|
77
|
+
remote_path = File.join(source, child.name)
|
78
|
+
children.push(remote_path)
|
79
|
+
end
|
80
|
+
new_target = File.join(target_dir, File.basename(source))
|
81
|
+
downloads.concat(sftp_download(sftp, children, new_target))
|
82
|
+
else
|
83
|
+
download = download_file(sftp, source, Helper::SftpHelper.get_target_file_path(source, target_dir))
|
84
|
+
downloads.push(download) unless download.nil?
|
85
|
+
end
|
86
|
+
rescue => e
|
87
|
+
UI.message("download for path #{source} failed: #{e}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
return downloads
|
91
|
+
end
|
92
|
+
|
93
|
+
# Downloads remote file
|
94
|
+
#
|
95
|
+
# @param sftp
|
96
|
+
# @param [String] remote_file_path
|
97
|
+
# @param [String] local_file_path
|
98
|
+
def download_file(sftp, remote_file_path, local_file_path)
|
99
|
+
UI.message('Checking remote file')
|
100
|
+
UI.message("remote path #{remote_file_path}")
|
101
|
+
download = nil
|
102
|
+
begin
|
103
|
+
sftp.stat!(remote_file_path) do |response|
|
104
|
+
if response.ok?
|
105
|
+
UI.success('Loading remote file:')
|
106
|
+
download = sftp.download(remote_file_path, local_file_path) do |event, _uploader, *_args|
|
107
|
+
case event
|
108
|
+
when :open then
|
109
|
+
UI.message("starting download of file #{remote_file_path} to #{local_file_path}")
|
110
|
+
when :finish then
|
111
|
+
UI.success("download of file #{remote_file_path} to #{local_file_path} successful")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
rescue => e
|
117
|
+
UI.message("remote file not found #{e}")
|
118
|
+
end
|
119
|
+
return download
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'fastlane_core'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Sftp
|
5
|
+
# Provides available options for the commands generator
|
6
|
+
class Options
|
7
|
+
def self.general_options
|
8
|
+
return [
|
9
|
+
FastlaneCore::ConfigItem.new(key: :server_url,
|
10
|
+
short_option: '-r',
|
11
|
+
optional: false,
|
12
|
+
env_name: 'SERVER_URL',
|
13
|
+
description: 'URL of your server'),
|
14
|
+
FastlaneCore::ConfigItem.new(key: :server_user,
|
15
|
+
short_option: '-u',
|
16
|
+
optional: false,
|
17
|
+
env_name: 'SERVER_USER',
|
18
|
+
description: 'USER of your server'),
|
19
|
+
FastlaneCore::ConfigItem.new(key: :server_password,
|
20
|
+
short_option: '-p',
|
21
|
+
optional: true,
|
22
|
+
env_name: 'SERVER_PASSWORD',
|
23
|
+
description: 'PASSWORD for your server (not for production)',
|
24
|
+
conflicting_options: [:server_key],
|
25
|
+
conflict_block: proc do |value|
|
26
|
+
UI.user_error!("You can't use 'password' and '#{value.key}' options in one run.")
|
27
|
+
end),
|
28
|
+
FastlaneCore::ConfigItem.new(key: :server_key,
|
29
|
+
short_option: '-k',
|
30
|
+
optional: false,
|
31
|
+
env_name: 'SERVER_KEY',
|
32
|
+
description: 'RSA key for your server',
|
33
|
+
conflicting_options: [:server_password],
|
34
|
+
conflict_block: proc do |value|
|
35
|
+
UI.user_error!("You can't use 'repo_key' and '#{value.key}' options in one run.")
|
36
|
+
end),
|
37
|
+
FastlaneCore::ConfigItem.new(key: :server_key_passphrase,
|
38
|
+
short_option: '-v',
|
39
|
+
optional: true,
|
40
|
+
env_name: 'SERVER_KEY_PASSPHRASE',
|
41
|
+
description: 'Optional passphrase for the RSA key for your server. If required but not provided, user will be asked for')
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.available_options_upload
|
46
|
+
return [].concat(general_options).concat(
|
47
|
+
[
|
48
|
+
FastlaneCore::ConfigItem.new(key: :target_dir,
|
49
|
+
short_option: '-x',
|
50
|
+
description: 'target path on the server relative to the home directory of the user'),
|
51
|
+
FastlaneCore::ConfigItem.new(key: :file_paths,
|
52
|
+
short_option: '-j',
|
53
|
+
description: 'List of files/folders to upload',
|
54
|
+
type: Array,
|
55
|
+
verify_block: proc do |value|
|
56
|
+
UI.user_error!("you must provide at least one file to upload") if value.empty?
|
57
|
+
value.each { |entry| UI.user_error!("file '#{entry}' does not exist") unless File.exist?(entry) }
|
58
|
+
end)
|
59
|
+
]
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.available_options_download
|
64
|
+
return [].concat(general_options).concat(
|
65
|
+
[
|
66
|
+
FastlaneCore::ConfigItem.new(key: :target_dir,
|
67
|
+
short_option: '-x',
|
68
|
+
optional: true,
|
69
|
+
description: 'local target path to a folder where all downloaded files should be put'),
|
70
|
+
FastlaneCore::ConfigItem.new(key: :file_paths,
|
71
|
+
short_option: '-j',
|
72
|
+
description: 'List of remote files/folders to download relative to the home directory of the user',
|
73
|
+
type: Array,
|
74
|
+
verify_block: proc do |value|
|
75
|
+
UI.user_error!("you must provide at least one file to download") if value.empty?
|
76
|
+
end)
|
77
|
+
]
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/sftp'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
7
|
+
|
8
|
+
module Helper
|
9
|
+
class SftpHelper
|
10
|
+
# class methods that you define here become available in your action
|
11
|
+
# as `Helper::SftpHelper.your_method`
|
12
|
+
#
|
13
|
+
|
14
|
+
def self.login(host, user, password, rsa_keypath, rsa_keypath_passphrase)
|
15
|
+
if host.nil? || user.nil?
|
16
|
+
UI.user_error('server_url, server_user and server_password or server_key must be set')
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
if rsa_keypath
|
21
|
+
rsa_key = Helper::SftpHelper.load_rsa_key(rsa_keypath)
|
22
|
+
if rsa_key.nil?
|
23
|
+
UI.user_error("Failed to load RSA key... #{rsa_keypath}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if !rsa_key.nil?
|
28
|
+
UI.message('Logging in with RSA key...')
|
29
|
+
session = Net::SSH.start(host, user, key_data: rsa_key, keys_only: true, passphrase: rsa_keypath_passphrase)
|
30
|
+
else
|
31
|
+
UI.message('Logging in with username/password...')
|
32
|
+
session = Net::SSH.start(host, user, password: password)
|
33
|
+
end
|
34
|
+
return session
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check file existence locally
|
38
|
+
#
|
39
|
+
# @param local_file_path
|
40
|
+
def self.check_file(local_file_path)
|
41
|
+
if File.exist?(local_file_path)
|
42
|
+
UI.verbose('File found at ' + local_file_path)
|
43
|
+
return true
|
44
|
+
else
|
45
|
+
UI.important("File at given path #{local_file_path} does not exist. File will be ignored")
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get_target_file_path(source_file_path, target_dir)
|
51
|
+
return File.join(target_dir, File.basename(source_file_path))
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.remote_mkdir(sftp, remote_path)
|
55
|
+
sftp.mkdir(remote_path)
|
56
|
+
rescue Net::SFTP::StatusException => e
|
57
|
+
raise if e.code != 11
|
58
|
+
UI.message("Remote dir #{remote_path} exists.")
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.load_rsa_key(rsa_keypath)
|
62
|
+
File.open(rsa_keypath, 'r') do |file|
|
63
|
+
rsa_key = [file.read]
|
64
|
+
if !rsa_key.nil?
|
65
|
+
UI.success('Successfully loaded RSA key...')
|
66
|
+
else
|
67
|
+
UI.user_error!('Failed to load RSA key...')
|
68
|
+
end
|
69
|
+
rsa_key
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.generate_remote_path(user, target_dir)
|
74
|
+
path = File.join('/', user, target_dir)
|
75
|
+
if user != "root"
|
76
|
+
path = File.join('/home', path)
|
77
|
+
end
|
78
|
+
path
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'net/sftp'
|
4
|
+
require 'fastlane_core'
|
5
|
+
require 'fastlane_core/languages'
|
6
|
+
|
7
|
+
require_relative 'options'
|
8
|
+
|
9
|
+
module Fastlane
|
10
|
+
module Sftp
|
11
|
+
# Responsible for performing upload SFTP operations
|
12
|
+
class Uploader
|
13
|
+
attr_accessor :options
|
14
|
+
|
15
|
+
#
|
16
|
+
# These want to be an input parameters:
|
17
|
+
#
|
18
|
+
|
19
|
+
attr_accessor :host
|
20
|
+
attr_accessor :user
|
21
|
+
attr_accessor :password
|
22
|
+
attr_accessor :rsa_keypath
|
23
|
+
attr_accessor :rsa_keypath_passphrase
|
24
|
+
attr_accessor :target_dir
|
25
|
+
attr_accessor :root_path
|
26
|
+
attr_accessor :files
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
self.options = options unless options.nil?
|
30
|
+
self.host = options[:server_url]
|
31
|
+
self.user = options[:server_user]
|
32
|
+
self.password = options[:server_password]
|
33
|
+
self.rsa_keypath = options[:server_key]
|
34
|
+
self.rsa_keypath_passphrase = options[:server_key_passphrase]
|
35
|
+
self.files = options[:file_paths]
|
36
|
+
self.target_dir = options[:target_dir]
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Upload files
|
41
|
+
#
|
42
|
+
|
43
|
+
def upload
|
44
|
+
# Login & Upload all files using RSA key or username/password
|
45
|
+
UI.message('upload...')
|
46
|
+
|
47
|
+
session = Helper::SftpHelper.login(host, user, password, rsa_keypath, rsa_keypath_passphrase)
|
48
|
+
if session.nil?
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
UI.message('Uploading files...')
|
52
|
+
session.sftp.connect do |sftp|
|
53
|
+
Helper::SftpHelper.remote_mkdir(sftp, Helper::SftpHelper.generate_remote_path(user, target_dir))
|
54
|
+
path = target_dir
|
55
|
+
|
56
|
+
uploads = []
|
57
|
+
files.each do |file|
|
58
|
+
next unless Helper::SftpHelper.check_file(file)
|
59
|
+
|
60
|
+
re = Helper::SftpHelper.get_target_file_path(file, target_dir)
|
61
|
+
if File.directory?(file)
|
62
|
+
Helper::SftpHelper.remote_mkdir(sftp, re)
|
63
|
+
end
|
64
|
+
uploads.push(upload_file(sftp, file, re))
|
65
|
+
end
|
66
|
+
uploads.each(&:wait)
|
67
|
+
|
68
|
+
# Lists the entries in a directory for verification
|
69
|
+
sftp.dir.foreach(path) do |entry|
|
70
|
+
UI.message(entry.longname)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
session.close
|
74
|
+
return true
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Upload file
|
80
|
+
#
|
81
|
+
# @param sftp
|
82
|
+
# @param [String] local_file_path
|
83
|
+
# @param [String] remote_file_path
|
84
|
+
def upload_file(sftp, local_file_path, remote_file_path)
|
85
|
+
unless Helper::SftpHelper.check_file(local_file_path)
|
86
|
+
UI.message("local file #{local_file_path} not found #{e}")
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
if File.file?(local_file_path)
|
91
|
+
type = "file"
|
92
|
+
else
|
93
|
+
type = "folder"
|
94
|
+
end
|
95
|
+
UI.message("starting upload of #{type} #{local_file_path} to #{local_file_path}")
|
96
|
+
return sftp.upload(local_file_path, remote_file_path) do |event, _uploader, *args|
|
97
|
+
case event
|
98
|
+
when :mkdir then
|
99
|
+
# args[0] : remote path name
|
100
|
+
UI.message("creating directory #{args[0]}")
|
101
|
+
when :open then
|
102
|
+
file = args[0]
|
103
|
+
UI.message("starting upload of #{file.local} to #{file.remote}")
|
104
|
+
when :close then
|
105
|
+
file = args[0]
|
106
|
+
UI.message("finished with #{file.remote}")
|
107
|
+
when :finish then
|
108
|
+
UI.success("upload of #{type} #{local_file_path} to #{remote_file_path} successful")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
metadata
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fastlane-plugin-sftp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Oliver Limberg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: net-ssh
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: net-sftp
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.1.2
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.1.2
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: pry
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bundler
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec_junit_formatter
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: rake
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: rubocop
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 0.49.1
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 0.49.1
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: rubocop-require_tools
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: simplecov
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: fastlane
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: 2.116.0
|
172
|
+
type: :development
|
173
|
+
prerelease: false
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: 2.116.0
|
179
|
+
description:
|
180
|
+
email: o.limberg@portrix.net
|
181
|
+
executables: []
|
182
|
+
extensions: []
|
183
|
+
extra_rdoc_files: []
|
184
|
+
files:
|
185
|
+
- LICENSE
|
186
|
+
- README.md
|
187
|
+
- lib/fastlane/plugin/sftp.rb
|
188
|
+
- lib/fastlane/plugin/sftp/actions/sftp_download.rb
|
189
|
+
- lib/fastlane/plugin/sftp/actions/sftp_upload.rb
|
190
|
+
- lib/fastlane/plugin/sftp/helper/downloader.rb
|
191
|
+
- lib/fastlane/plugin/sftp/helper/options.rb
|
192
|
+
- lib/fastlane/plugin/sftp/helper/sftp_helper.rb
|
193
|
+
- lib/fastlane/plugin/sftp/helper/uploader.rb
|
194
|
+
- lib/fastlane/plugin/sftp/version.rb
|
195
|
+
homepage: https://github.com/oklimberg/fastlane-plugin-sftp
|
196
|
+
licenses:
|
197
|
+
- MIT
|
198
|
+
metadata: {}
|
199
|
+
post_install_message:
|
200
|
+
rdoc_options: []
|
201
|
+
require_paths:
|
202
|
+
- lib
|
203
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - ">="
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '0'
|
208
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
requirements: []
|
214
|
+
rubyforge_project:
|
215
|
+
rubygems_version: 2.5.2.3
|
216
|
+
signing_key:
|
217
|
+
specification_version: 4
|
218
|
+
summary: Plugin to upload files via SFTP
|
219
|
+
test_files: []
|