fastlane-ext 1.0.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 +7 -0
- data/lib/fastlane-ext.rb +10 -0
- data/lib/fastlane-ext/app_release.rb +99 -0
- data/lib/fastlane-ext/app_release_manager.rb +118 -0
- data/lib/fastlane-ext/project_controller.rb +82 -0
- data/lib/fastlane-ext/telegram.rb +87 -0
- data/lib/fastlane-ext/telegram_notifier.rb +26 -0
- data/lib/fastlane-ext/upload_dsym.rb +148 -0
- data/lib/fastlane-ext/upload_to_s3.rb +146 -0
- data/lib/fastlane-ext/version.rb +5 -0
- metadata +177 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 15f38ec11ae724289c6f0320066d462f7a3809a3c43fd4cf83e3a497d53e2fe1
|
4
|
+
data.tar.gz: a521c75cd50c016d071042f81d2ae779eeb7e0bcf4dc8b38e9bc9565583eed1e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4994676c7567d185ec194e9e31e5f7fd458c2c7196c3cd4738e92b6dc1e28ac4596d37877b51478ddd66025d0f780ac812f312b8268914d223f0938625ce01f3
|
7
|
+
data.tar.gz: a564c1eed8297550958b86d6a45c3c560de7607c80213163d3db65a224d92adcc044b2f9c78d0f133fbb54a3c37b2c25e12f3e44bbdd8d7f2ae257bf23eaa12e
|
data/lib/fastlane-ext.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fastlane-ext/version'
|
4
|
+
require_relative 'fastlane-ext/telegram'
|
5
|
+
require_relative 'fastlane-ext/app_release'
|
6
|
+
require_relative 'fastlane-ext/upload_dsym'
|
7
|
+
require_relative 'fastlane-ext/upload_to_s3'
|
8
|
+
|
9
|
+
module FastlaneExt
|
10
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'app_release_manager'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
module Actions
|
7
|
+
class AppReleaseAction < Action
|
8
|
+
def self.run(params)
|
9
|
+
FastlaneExt::AppReleaseManager.new(
|
10
|
+
params[:schemes],
|
11
|
+
params[:project],
|
12
|
+
params[:branch],
|
13
|
+
params[:version],
|
14
|
+
params[:target_suffix]
|
15
|
+
).release
|
16
|
+
end
|
17
|
+
|
18
|
+
#####################################################
|
19
|
+
# @!group Documentation
|
20
|
+
#####################################################
|
21
|
+
|
22
|
+
def self.description
|
23
|
+
'Release app according to the version'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.details
|
27
|
+
'Release app according to the version'
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.available_options
|
31
|
+
[
|
32
|
+
FastlaneCore::ConfigItem.new(
|
33
|
+
key: :schemes,
|
34
|
+
description: 'schemes',
|
35
|
+
type: Array,
|
36
|
+
verify_block: proc do |value|
|
37
|
+
msg = 'invalid or empty schemes'
|
38
|
+
UI.user_error!(msg) if value.empty?
|
39
|
+
end
|
40
|
+
),
|
41
|
+
FastlaneCore::ConfigItem.new(
|
42
|
+
key: :project,
|
43
|
+
description: 'path to xcodeproj',
|
44
|
+
default_value: Dir.glob('*.xcodeproj').first,
|
45
|
+
verify_block: proc do |value|
|
46
|
+
msg = 'xcodeproj not found'
|
47
|
+
UI.user_error!(msg) unless File.directory?(value)
|
48
|
+
end
|
49
|
+
),
|
50
|
+
FastlaneCore::ConfigItem.new(
|
51
|
+
key: :branch,
|
52
|
+
description: 'branch',
|
53
|
+
default_value: 'master',
|
54
|
+
verify_block: proc do |value|
|
55
|
+
UI.user_error!('invalid branch') if value.empty?
|
56
|
+
end
|
57
|
+
),
|
58
|
+
FastlaneCore::ConfigItem.new(
|
59
|
+
key: :version,
|
60
|
+
description: 'app version (like 1.1.0)',
|
61
|
+
optional: true
|
62
|
+
),
|
63
|
+
FastlaneCore::ConfigItem.new(
|
64
|
+
key: :target_suffix,
|
65
|
+
description: 'Specific target suffix',
|
66
|
+
optional: true
|
67
|
+
)
|
68
|
+
]
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.example_code
|
72
|
+
[
|
73
|
+
'app_release(
|
74
|
+
schemes: ["AppScheme", "AppExtension"]
|
75
|
+
)',
|
76
|
+
'app_release(
|
77
|
+
schemes: ["AppScheme", "AppExtension"],
|
78
|
+
project: "/path/to/xcodeproj",
|
79
|
+
branch: "master",
|
80
|
+
version: "2.3.0",
|
81
|
+
target_suffix: "_sfx"
|
82
|
+
)'
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.authors
|
87
|
+
%w[sroik]
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.is_supported?(platform)
|
91
|
+
platform == :ios
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.category
|
95
|
+
:notifications
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'project_controller'
|
4
|
+
require 'fastlane_core/ui/ui'
|
5
|
+
|
6
|
+
module FastlaneExt
|
7
|
+
module SharedValues
|
8
|
+
APP_RELEASE_VERSION = 'APP_RELEASE_VERSION'
|
9
|
+
APP_RELEASE_BUILD_NUMBER = 'APP_RELEASE_BUILD_NUMBER'
|
10
|
+
APP_RELEASE_VERSION_TAG = 'APP_RELEASE_VERSION_TAG'
|
11
|
+
end
|
12
|
+
|
13
|
+
class AppReleaseManager
|
14
|
+
include FastlaneCore
|
15
|
+
include Gem
|
16
|
+
|
17
|
+
def initialize(schemes, project, branch, version = nil, target_suffix = nil)
|
18
|
+
raise 'Invalid Version' if version && !version_valid?(version)
|
19
|
+
|
20
|
+
@scheme = schemes.first
|
21
|
+
@branch = branch
|
22
|
+
@target_suffix = target_suffix
|
23
|
+
@project_controller = ProjectController.new(project, schemes)
|
24
|
+
@version = version.nil? ? @project_controller.version : Version.new(version)
|
25
|
+
end
|
26
|
+
|
27
|
+
def release
|
28
|
+
bump_version
|
29
|
+
archive
|
30
|
+
upload_to_tf
|
31
|
+
update_env
|
32
|
+
@project_controller.bump_build_version_patch
|
33
|
+
push_version_bump
|
34
|
+
|
35
|
+
remove_existing_git_tag
|
36
|
+
push_git_tag
|
37
|
+
end
|
38
|
+
|
39
|
+
def bump_version
|
40
|
+
msg = 'Given version is less than the actual app version'
|
41
|
+
UI.user_error! msg if @version < @project_controller.version
|
42
|
+
return unless @version > @project_controller.version
|
43
|
+
|
44
|
+
@project_controller.set_version(@version)
|
45
|
+
@project_controller.set_build_version(Version.new(@version.to_s + '.0'))
|
46
|
+
UI.success "Version was successfully bumped to #{version_dump}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def upload_to_tf
|
50
|
+
# see more at https://github.com/fastlane/fastlane/issues/15390
|
51
|
+
ENV['DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS'] = '-t DAV'
|
52
|
+
cmd = 'fastlane pilot upload --skip_submission --skip_waiting_for_build_processing'
|
53
|
+
raise "TF uploading Failed! Command execution error: '#{cmd}'" unless system(cmd)
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_env
|
57
|
+
ENV[SharedValues::APP_RELEASE_VERSION] = @project_controller.version.to_s
|
58
|
+
ENV[SharedValues::APP_RELEASE_BUILD_NUMBER] = @project_controller.build_version.to_s
|
59
|
+
ENV[SharedValues::APP_RELEASE_VERSION_TAG] = version_dump
|
60
|
+
end
|
61
|
+
|
62
|
+
def push_version_bump
|
63
|
+
cmd = "git pull origin HEAD:#{@branch}"
|
64
|
+
raise "Git Pull Failed! Command execution error: '#{cmd}'" unless system(cmd)
|
65
|
+
|
66
|
+
cmd = "git add . && git commit -m 'Bump version to #{version_dump}'"
|
67
|
+
raise "Git Commit Failed! Command execution error: '#{cmd}'" unless system(cmd)
|
68
|
+
|
69
|
+
cmd = "git push origin HEAD:#{@branch}"
|
70
|
+
raise "Git Push Failed! Command execution error: '#{cmd}'" unless system(cmd)
|
71
|
+
end
|
72
|
+
|
73
|
+
def archive
|
74
|
+
cmd = "fastlane gym --configuration Release --scheme #{@scheme} --export_method app-store"
|
75
|
+
raise "Archiving failed! Command execution error: '#{cmd}'" unless system(cmd)
|
76
|
+
end
|
77
|
+
|
78
|
+
def push_git_tag
|
79
|
+
UI.message "going to push tag: #{curr_git_tag}"
|
80
|
+
cmd = "git tag #{curr_git_tag} && git push --tags"
|
81
|
+
raise "Tag push failed! Command execution error: '#{cmd}'" unless system(cmd)
|
82
|
+
end
|
83
|
+
|
84
|
+
def remove_existing_git_tag
|
85
|
+
tag = existing_git_tag
|
86
|
+
return if tag.nil?
|
87
|
+
|
88
|
+
UI.message "going to remove tag: #{tag}"
|
89
|
+
cmd = "git tag -d #{tag} && git push origin :refs/tags/#{tag}"
|
90
|
+
raise "Git tag deletion failed! Command execution error: '#{cmd}'" unless system(cmd)
|
91
|
+
end
|
92
|
+
|
93
|
+
def curr_git_tag
|
94
|
+
return @version.to_s unless @target_suffix
|
95
|
+
|
96
|
+
"#{@version}_#{@target_suffix}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def existing_git_tag
|
100
|
+
git_tags.detect do |t|
|
101
|
+
tag_v = t.match(/[0-9.]+/)[0]
|
102
|
+
version_valid?(tag_v) && Version.new(tag_v) == @version
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def git_tags
|
107
|
+
`git tag`.split("\n")
|
108
|
+
end
|
109
|
+
|
110
|
+
def version_valid?(version)
|
111
|
+
version.to_s.match?(/^\d\.\d\.\d{1,3}$/)
|
112
|
+
end
|
113
|
+
|
114
|
+
def version_dump
|
115
|
+
"#{@project_controller.version}/#{@project_controller.build_version}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xcodeproj'
|
4
|
+
|
5
|
+
module FastlaneExt
|
6
|
+
class ProjectController
|
7
|
+
include Gem
|
8
|
+
|
9
|
+
def initialize(path, schemes)
|
10
|
+
raise 'Invalid Path' unless File.directory?(path)
|
11
|
+
|
12
|
+
@project = Xcodeproj::Project.open(path)
|
13
|
+
@schemes = schemes
|
14
|
+
end
|
15
|
+
|
16
|
+
def bump_build_version_patch
|
17
|
+
value = build_version.to_s
|
18
|
+
value[-1] = (value[-1].to_i + 1).to_s
|
19
|
+
set_build_version(Version.new(value))
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_version(version)
|
23
|
+
@schemes.each do |s|
|
24
|
+
set_scheme_value_for_key(s, version.to_s, version_key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_build_version(version)
|
29
|
+
@schemes.each do |s|
|
30
|
+
set_scheme_value_for_key(s, version.to_s, build_version_key)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def version
|
35
|
+
value = scheme_value_for_key(@schemes.first, version_key)
|
36
|
+
Version.new(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_version
|
40
|
+
value = scheme_value_for_key(@schemes.first, build_version_key)
|
41
|
+
Version.new(value)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def set_scheme_value_for_key(scheme, value, key, configuration = nil)
|
47
|
+
target = project_target(scheme)
|
48
|
+
target.build_configurations.each do |config|
|
49
|
+
config.build_settings[key] = value if configuration.nil? || config.name == configuration
|
50
|
+
end
|
51
|
+
|
52
|
+
@project.save
|
53
|
+
end
|
54
|
+
|
55
|
+
def scheme_value_for_key(scheme, key, configuration = nil)
|
56
|
+
target = project_target(scheme)
|
57
|
+
target.build_configurations.each do |config|
|
58
|
+
if configuration.nil? || config.name == configuration
|
59
|
+
value = config.build_settings[key]
|
60
|
+
return value if value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def project_target(scheme)
|
68
|
+
target = @project.targets.find { |t| t.name == scheme }
|
69
|
+
raise "Target not found for scheme: #{scheme}" unless target
|
70
|
+
|
71
|
+
target
|
72
|
+
end
|
73
|
+
|
74
|
+
def version_key
|
75
|
+
'MARKETING_VERSION'
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_version_key
|
79
|
+
'CURRENT_PROJECT_VERSION'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'telegram_notifier'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
module Actions
|
7
|
+
class TelegramAction < Action
|
8
|
+
include FastlaneExt
|
9
|
+
|
10
|
+
def self.run(params)
|
11
|
+
notifier = TelegramNotifier.new(bot_api_token: params[:bot_api_token], chat_id: params[:chat_id])
|
12
|
+
notifier.notify(message: params[:message], parse_mode: params[:parse_mode])
|
13
|
+
end
|
14
|
+
|
15
|
+
#####################################################
|
16
|
+
# @!group Documentation
|
17
|
+
#####################################################
|
18
|
+
|
19
|
+
def self.description
|
20
|
+
'Send a success/error message to your Telegram group'
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.details
|
24
|
+
'Send a success/error message to your Telegram group'
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.available_options
|
28
|
+
[
|
29
|
+
FastlaneCore::ConfigItem.new(
|
30
|
+
key: :bot_api_token,
|
31
|
+
env_name: 'FL_TELEGRAM_BOT_API_TOKEN',
|
32
|
+
description: 'API Token for telegram bot',
|
33
|
+
verify_block: proc do |value|
|
34
|
+
msg = "No bot API token for TelegramAction given, pass using `bot_api_token: 'token'`"
|
35
|
+
UI.user_error!(msg) unless value && !value.empty?
|
36
|
+
end
|
37
|
+
),
|
38
|
+
FastlaneCore::ConfigItem.new(
|
39
|
+
key: :message,
|
40
|
+
env_name: 'FL_TELEGRAM_MESSAGE',
|
41
|
+
description: 'The message that should be displayed on Telegram',
|
42
|
+
optional: true
|
43
|
+
),
|
44
|
+
FastlaneCore::ConfigItem.new(
|
45
|
+
key: :chat_id,
|
46
|
+
env_name: 'FL_TELEGRAM_CHAT_ID',
|
47
|
+
description: 'telegram chat id',
|
48
|
+
verify_block: proc do |value|
|
49
|
+
msg = "No chat id for TelegramAction given, pass using `chat_id: 'chat id'`"
|
50
|
+
UI.user_error!(msg) unless value && !value.empty?
|
51
|
+
end
|
52
|
+
),
|
53
|
+
FastlaneCore::ConfigItem.new(
|
54
|
+
key: :parse_mode,
|
55
|
+
env_name: 'FL_TELEGRAM_MESSAGE_PARSE_MODE',
|
56
|
+
description: 'telegram message parse mode',
|
57
|
+
optional: true
|
58
|
+
)
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.example_code
|
63
|
+
[
|
64
|
+
'telegram(message: "App successfully released!")',
|
65
|
+
'telegram(
|
66
|
+
bot_api_token: "bot api token here",
|
67
|
+
chat_id: "telegram chat id here",
|
68
|
+
message: "message here"
|
69
|
+
parse_mode: "message parse mode here"
|
70
|
+
)'
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.authors
|
75
|
+
%w[sroik elfenlaid]
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.is_supported?(platform)
|
79
|
+
platform == :ios
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.category
|
83
|
+
:notifications
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/https'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module FastlaneExt
|
7
|
+
HTML = 'HTML'
|
8
|
+
MARKDOWN = 'Markdown'
|
9
|
+
|
10
|
+
class TelegramNotifier
|
11
|
+
def initialize(bot_api_token:, chat_id:)
|
12
|
+
raise 'Invalid Bot Api Token' if bot_api_token.empty?
|
13
|
+
raise 'Invalid Chat Id' if chat_id.empty?
|
14
|
+
|
15
|
+
@bot_api_token = bot_api_token
|
16
|
+
@chat_id = chat_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def notify(message:, parse_mode: nil)
|
20
|
+
uri = URI.parse("https://api.telegram.org/bot#{@bot_api_token}/sendMessage")
|
21
|
+
params = { text: message, chat_id: @chat_id }
|
22
|
+
params[:parse_mode] = parse_mode unless parse_mode.nil?
|
23
|
+
Net::HTTP.post_form(uri, params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Actions
|
5
|
+
class UploadDsymAction < Action
|
6
|
+
def self.run(params)
|
7
|
+
require 'aws-sdk-s3'
|
8
|
+
|
9
|
+
kind = params[:kind]
|
10
|
+
version = params[:version]
|
11
|
+
dsym_path = params[:dSYM]
|
12
|
+
dsym_name = File.basename(dsym_path, '.*')
|
13
|
+
dsym_ext = File.extname(dsym_path)
|
14
|
+
|
15
|
+
bucket = params[:space] || params[:bucket]
|
16
|
+
acl = params[:acl]
|
17
|
+
file_key = [dsym_name, kind, version].join('_') + dsym_ext
|
18
|
+
file_path = params[:space] ? params[:bucket] + '/' + file_key : file_key
|
19
|
+
|
20
|
+
client = Aws::S3::Client.new(
|
21
|
+
access_key_id: params[:access_key],
|
22
|
+
secret_access_key: params[:secret_access_key],
|
23
|
+
endpoint: params[:endpoint],
|
24
|
+
region: params[:region]
|
25
|
+
)
|
26
|
+
|
27
|
+
UI.message "Check whether destination bucket #{bucket} exists..💤"
|
28
|
+
begin
|
29
|
+
response = client.create_bucket(
|
30
|
+
bucket: bucket,
|
31
|
+
acl: acl
|
32
|
+
)
|
33
|
+
UI.message "Bucket #{bucket} created! ✨"
|
34
|
+
rescue Aws::S3::Errors::BucketAlreadyExists
|
35
|
+
UI.message "Bucket #{bucket} alredy exists 👌"
|
36
|
+
end
|
37
|
+
|
38
|
+
UI.message 'Going to upload dSYM..💤'
|
39
|
+
File.open(dsym_path, 'r') do |body|
|
40
|
+
response = client.put_object(
|
41
|
+
acl: acl,
|
42
|
+
bucket: bucket,
|
43
|
+
key: file_path,
|
44
|
+
body: body
|
45
|
+
)
|
46
|
+
|
47
|
+
UI.message "dSYM uploaded to #{file_path} ✨"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#####################################################
|
52
|
+
# @!group Documentation
|
53
|
+
#####################################################
|
54
|
+
|
55
|
+
def self.description
|
56
|
+
'Upload dSYM archive to S3 or Spaces'
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.available_options
|
60
|
+
[
|
61
|
+
FastlaneCore::ConfigItem.new(key: :kind,
|
62
|
+
env_name: 'FL_UPLOAD_DSYM_KIND',
|
63
|
+
description: "Origin of the dSYM ('Beta', 'Release', etc)",
|
64
|
+
is_string: true,
|
65
|
+
default_value: ENV['BITRISE_TRIGGERED_WORKFLOW_TITLE'],
|
66
|
+
verify_block: proc do |value|
|
67
|
+
UI.user_error!("No kind for UploadDsymAction given, pass using `kind: 'kind'`") unless value && !value.empty?
|
68
|
+
end),
|
69
|
+
FastlaneCore::ConfigItem.new(key: :version,
|
70
|
+
env_name: 'FL_UPLOAD_DSYM_VERSION',
|
71
|
+
description: "Version of a constructed .ipa. (Build number '321', App version '1.2.3', etc.)",
|
72
|
+
is_string: true,
|
73
|
+
default_value: ENV['APP_RELEASE_BUILD_NUMBER'] || ENV['BITRISE_BUILD_NUMBER'],
|
74
|
+
verify_block: proc do |value|
|
75
|
+
UI.user_error!("No version for UploadDsymAction given, pass using `version: 'version'`") unless value && !value.empty?
|
76
|
+
end),
|
77
|
+
FastlaneCore::ConfigItem.new(key: :dSYM,
|
78
|
+
env_name: 'FL_UPLOAD_DSYM_PATH',
|
79
|
+
description: 'Archived dSYM files',
|
80
|
+
is_string: true,
|
81
|
+
default_value: ENV['DSYM_OUTPUT_PATH'] || Dir['*.dSYM.zip'].first,
|
82
|
+
verify_block: proc do |value|
|
83
|
+
UI.user_error!("Couldn't find dSYM file at path '#{value}'") unless File.exist?(value)
|
84
|
+
end),
|
85
|
+
FastlaneCore::ConfigItem.new(key: :region,
|
86
|
+
env_name: 'FL_UPLOAD_DSYM_REGION',
|
87
|
+
description: 'Region for S3 or Spaces',
|
88
|
+
is_string: true,
|
89
|
+
default_value: 'ams3',
|
90
|
+
verify_block: proc do |value|
|
91
|
+
UI.user_error!("No region for UploadDsymAction given, pass using `region: 'region'`") unless value && !value.empty?
|
92
|
+
end),
|
93
|
+
FastlaneCore::ConfigItem.new(key: :endpoint,
|
94
|
+
env_name: 'FL_UPLOAD_DSYM_ENDPOINT',
|
95
|
+
description: 'Endpoint for S3 or Spaces',
|
96
|
+
is_string: true,
|
97
|
+
default_value: 'https://ams3.digitaloceanspaces.com',
|
98
|
+
verify_block: proc do |value|
|
99
|
+
UI.user_error!("No Endpoint for UploadDsymAction given, pass using `endpoint: 'endpoint'`") unless value && !value.empty?
|
100
|
+
end),
|
101
|
+
FastlaneCore::ConfigItem.new(key: :access_key,
|
102
|
+
env_name: 'FL_UPLOAD_DSYM_S3_ACCESS_KEY',
|
103
|
+
description: 'Access Key for S3 or Spaces',
|
104
|
+
is_string: true,
|
105
|
+
verify_block: proc do |value|
|
106
|
+
raise "No Access Key for UploadDsymAction given, pass using `access_key: 'access_key'`".red unless value && !value.empty?
|
107
|
+
end),
|
108
|
+
FastlaneCore::ConfigItem.new(key: :secret_access_key,
|
109
|
+
env_name: 'FL_UPLOAD_DSYM_S3_SECRET_ACCESS_KEY',
|
110
|
+
description: 'Secret Access Key for S3 or Spaces',
|
111
|
+
is_string: true,
|
112
|
+
verify_block: proc do |value|
|
113
|
+
raise "No Secret Access Key for UploadDsymAction given, pass using `secret_access_key: 'secret_access_key'`".red unless value && !value.empty?
|
114
|
+
end),
|
115
|
+
FastlaneCore::ConfigItem.new(key: :bucket,
|
116
|
+
env_name: 'FL_UPLOAD_DSYM_S3_BUCKET',
|
117
|
+
description: 'Bucket for S3 or Spaces',
|
118
|
+
is_string: true,
|
119
|
+
default_value: 'default',
|
120
|
+
verify_block: proc do |value|
|
121
|
+
raise "No Bucket for UploadToS3Action given, pass using `bucket: 'bucket'`".red unless value && !value.empty?
|
122
|
+
end),
|
123
|
+
FastlaneCore::ConfigItem.new(key: :space,
|
124
|
+
env_name: 'FL_UPLOAD_DSYM_SPACE',
|
125
|
+
description: 'Digital Ocean Space',
|
126
|
+
is_string: true,
|
127
|
+
default_value: 'project-dsym'),
|
128
|
+
FastlaneCore::ConfigItem.new(key: :acl,
|
129
|
+
env_name: 'FL_UPLOAD_DSYM_S3_ACL',
|
130
|
+
description: 'Access level for the file',
|
131
|
+
is_string: true,
|
132
|
+
default_value: 'private',
|
133
|
+
verify_block: proc do |value|
|
134
|
+
raise "No Bucket for UploadToS3Action given, pass using `bucket: 'bucket'`".red unless value && !value.empty?
|
135
|
+
end)
|
136
|
+
]
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.authors
|
140
|
+
['https://github.com/sroik', 'https://github.com/elfenlaid']
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.is_supported?(platform)
|
144
|
+
platform == :ios
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Actions
|
5
|
+
module SharedValues
|
6
|
+
UPLOADED_S3_URL = 'UPLOAD_S3_URL'
|
7
|
+
end
|
8
|
+
|
9
|
+
class UploadToS3Action < Action
|
10
|
+
def self.run(params)
|
11
|
+
require 'aws-sdk-s3'
|
12
|
+
|
13
|
+
local_path = params[:path]
|
14
|
+
local_name = File.basename(local_path)
|
15
|
+
|
16
|
+
bucket = params[:space] || params[:bucket]
|
17
|
+
acl = params[:acl]
|
18
|
+
file_key = local_name
|
19
|
+
file_path = params[:space] ? params[:bucket] + '/' + file_key : file_key
|
20
|
+
|
21
|
+
client = Aws::S3::Client.new(
|
22
|
+
access_key_id: params[:access_key],
|
23
|
+
secret_access_key: params[:secret_access_key],
|
24
|
+
endpoint: params[:endpoint],
|
25
|
+
region: params[:region]
|
26
|
+
)
|
27
|
+
|
28
|
+
UI.message "Check whether destination bucket #{bucket} exists..💤"
|
29
|
+
|
30
|
+
begin
|
31
|
+
response = client.create_bucket(
|
32
|
+
bucket: bucket,
|
33
|
+
acl: 'private'
|
34
|
+
)
|
35
|
+
UI.message "✨ Bucket #{bucket} created! ✨"
|
36
|
+
rescue Aws::S3::Errors::BucketAlreadyExists
|
37
|
+
UI.message "Bucket #{bucket} alredy exists 👌"
|
38
|
+
end
|
39
|
+
|
40
|
+
UI.message 'Going to upload file to s3..💤'
|
41
|
+
|
42
|
+
File.open(local_path, 'r') do |body|
|
43
|
+
response = client.put_object(
|
44
|
+
acl: acl,
|
45
|
+
bucket: bucket,
|
46
|
+
key: file_path,
|
47
|
+
body: body
|
48
|
+
)
|
49
|
+
|
50
|
+
object = Aws::S3::Object.new(
|
51
|
+
key: file_path,
|
52
|
+
bucket_name: bucket,
|
53
|
+
client: client
|
54
|
+
)
|
55
|
+
|
56
|
+
url = object.public_url
|
57
|
+
|
58
|
+
UI.message "✨ file uploaded to #{url} ✨"
|
59
|
+
ENV[SharedValues::UPLOADED_S3_URL] = url
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
#####################################################
|
64
|
+
# @!group Documentation
|
65
|
+
#####################################################
|
66
|
+
|
67
|
+
def self.description
|
68
|
+
'Upload file to S3 or Spaces'
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.available_options
|
72
|
+
[
|
73
|
+
FastlaneCore::ConfigItem.new(key: :path,
|
74
|
+
env_name: 'FL_UPLOAD_S3_PATH',
|
75
|
+
description: 'Upload local path',
|
76
|
+
is_string: true,
|
77
|
+
verify_block: proc do |value|
|
78
|
+
UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value)
|
79
|
+
end),
|
80
|
+
FastlaneCore::ConfigItem.new(key: :region,
|
81
|
+
env_name: 'FL_UPLOAD_S3_REGION',
|
82
|
+
description: 'Region for S3 or Spaces',
|
83
|
+
is_string: true,
|
84
|
+
default_value: 'ams3',
|
85
|
+
verify_block: proc do |value|
|
86
|
+
UI.user_error!("No region for UploadToS3Action given, pass using `region: 'region'`") unless value && !value.empty?
|
87
|
+
end),
|
88
|
+
FastlaneCore::ConfigItem.new(key: :endpoint,
|
89
|
+
env_name: 'FL_UPLOAD_S3_ENDPOINT',
|
90
|
+
description: 'Endpoint for S3 or Spaces',
|
91
|
+
is_string: true,
|
92
|
+
default_value: 'https://ams3.digitaloceanspaces.com',
|
93
|
+
verify_block: proc do |value|
|
94
|
+
UI.user_error!("No Endpoint for UploadToS3Action given, pass using `endpoint: 'endpoint'`") unless value && !value.empty?
|
95
|
+
end),
|
96
|
+
FastlaneCore::ConfigItem.new(key: :access_key,
|
97
|
+
env_name: 'FL_UPLOAD_S3_ACCESS_KEY',
|
98
|
+
description: 'Access Key for S3 or Spaces',
|
99
|
+
is_string: true,
|
100
|
+
verify_block: proc do |value|
|
101
|
+
raise "No Access Key for UploadToS3Action given, pass using `access_key: 'access_key'`".red unless value && !value.empty?
|
102
|
+
end),
|
103
|
+
FastlaneCore::ConfigItem.new(key: :secret_access_key,
|
104
|
+
env_name: 'FL_UPLOAD_S3_SECRET_ACCESS_KEY',
|
105
|
+
description: 'Secret Access Key for S3 or Spaces',
|
106
|
+
is_string: true,
|
107
|
+
verify_block: proc do |value|
|
108
|
+
raise "No Secret Access Key for UploadToS3Action given, pass using `secret_access_key: 'secret_access_key'`".red unless value && !value.empty?
|
109
|
+
end),
|
110
|
+
FastlaneCore::ConfigItem.new(key: :bucket,
|
111
|
+
env_name: 'FL_UPLOAD_S3_BUCKET',
|
112
|
+
description: 'Bucket for S3 or Spaces',
|
113
|
+
is_string: true,
|
114
|
+
verify_block: proc do |value|
|
115
|
+
raise "No Bucket for UploadToS3Action given, pass using `bucket: 'bucket'`".red unless value && !value.empty?
|
116
|
+
end),
|
117
|
+
FastlaneCore::ConfigItem.new(key: :space,
|
118
|
+
env_name: 'FL_UPLOAD_S3_SPACE',
|
119
|
+
description: 'Digital Ocean Space',
|
120
|
+
is_string: true,
|
121
|
+
default_value: 'company-files'),
|
122
|
+
FastlaneCore::ConfigItem.new(key: :acl,
|
123
|
+
env_name: 'FL_UPLOAD_S3_ACL',
|
124
|
+
description: 'Access level for the file',
|
125
|
+
is_string: true,
|
126
|
+
default_value: 'public-read',
|
127
|
+
verify_block: proc do |value|
|
128
|
+
raise "No Bucket for UploadToS3Action given, pass using `bucket: 'bucket'`".red unless value && !value.empty?
|
129
|
+
end)
|
130
|
+
]
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.authors
|
134
|
+
['https://github.com/sroik', 'https://github.com/elfenlaid']
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.output
|
138
|
+
['UPLOADED_S3_URL': 'Uploaded file s3 path']
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.is_supported?(platform)
|
142
|
+
%i[ios android].include?(platform)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fastlane-ext
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- sroik
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-s3
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: fastlane
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: xcodeproj
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: gem-release
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.52'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.52'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: test-unit
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: fastlane ext
|
140
|
+
email: vasili.kazhanouski@gmail.com
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- lib/fastlane-ext.rb
|
146
|
+
- lib/fastlane-ext/app_release.rb
|
147
|
+
- lib/fastlane-ext/app_release_manager.rb
|
148
|
+
- lib/fastlane-ext/project_controller.rb
|
149
|
+
- lib/fastlane-ext/telegram.rb
|
150
|
+
- lib/fastlane-ext/telegram_notifier.rb
|
151
|
+
- lib/fastlane-ext/upload_dsym.rb
|
152
|
+
- lib/fastlane-ext/upload_to_s3.rb
|
153
|
+
- lib/fastlane-ext/version.rb
|
154
|
+
homepage: https://github.com/appsurd/fastlane-ext.git
|
155
|
+
licenses:
|
156
|
+
- MIT
|
157
|
+
metadata: {}
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
requirements: []
|
173
|
+
rubygems_version: 3.0.3
|
174
|
+
signing_key:
|
175
|
+
specification_version: 4
|
176
|
+
summary: fastlane ext summary
|
177
|
+
test_files: []
|