fastlane-plugin-polidea 3.0.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -6
- data/lib/fastlane/plugin/polidea/actions/shuttle.rb +73 -32
- data/lib/fastlane/plugin/polidea/helper/s3.rb +30 -0
- data/lib/fastlane/plugin/polidea/helper/shuttle.rb +9 -3
- data/lib/fastlane/plugin/polidea/version.rb +1 -1
- metadata +11 -12
- data/lib/fastlane/plugin/polidea/actions/fota_mail.rb +0 -187
- data/lib/fastlane/plugin/polidea/actions/fota_s3.rb +0 -568
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16148ca5e32380ed55cb696df4722d1f17692425705a1a457ecee71fec18ae2d
|
4
|
+
data.tar.gz: 6538bb9941484012d8881a883188b2155c8f38bad3968070c75f5423225e0524
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf3e04301c39c543817ece108bdf4f5fe441a905dfb7c015f67c7c27eb609e406a648419d21ebd3e58c5c09c60b5e86a70205f5490fa298a13e228b5634db358
|
7
|
+
data.tar.gz: d94d95510d05f9713461f2198b8445b927cbd83e70d0f72e93433803aac7ba1d596dae12cf48f6a47c81cc1265a8dabe698c5de91e226c91f65495aa605aafb7
|
data/README.md
CHANGED
@@ -17,8 +17,6 @@ fastlane add_plugin polidea
|
|
17
17
|
Plugin contains following actions:
|
18
18
|
- `extract_app_info`: Extracts application name, icon, version, binary size from .apk/.ipa
|
19
19
|
- `release_notes`: Extracts release notes from git tag message
|
20
|
-
- `fota_s3`: Custom version of s3 action with Polidea's installation page
|
21
|
-
- `fota_mail`: Custom version of mailgun action with Polidea's mail template
|
22
20
|
- `shuttle`: Upload new app to Shuttle
|
23
21
|
|
24
22
|
See more details [here](./docs/Actions.md).
|
@@ -33,10 +31,7 @@ fastlane actions
|
|
33
31
|
lane :deploy do
|
34
32
|
(some actions that produces .ipa/.apk)
|
35
33
|
extract_app_info
|
36
|
-
|
37
|
-
fota_mail(
|
38
|
-
to: "hey@polidea.com"
|
39
|
-
)
|
34
|
+
shuttle
|
40
35
|
end
|
41
36
|
```
|
42
37
|
|
@@ -44,6 +39,10 @@ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plu
|
|
44
39
|
|
45
40
|
**Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
|
46
41
|
|
42
|
+
## Migration guide
|
43
|
+
|
44
|
+
See [MIGRATION.md](./MIGRATION.md)
|
45
|
+
|
47
46
|
## Troubleshooting
|
48
47
|
|
49
48
|
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://github.com/fastlane/fastlane/blob/master/fastlane/docs/PluginsTroubleshooting.md) doc in the main `fastlane` repo.
|
@@ -10,9 +10,11 @@ module Fastlane
|
|
10
10
|
platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME].to_sym
|
11
11
|
options = {
|
12
12
|
api_token: params[:api_token],
|
13
|
-
|
13
|
+
ipa: params[:ipa],
|
14
|
+
apk: params[:apk],
|
15
|
+
dsym: params[:dsym],
|
16
|
+
mapping: params[:mapping],
|
14
17
|
prefix_schema: params[:prefix_schema],
|
15
|
-
apk_url: params[:apk_url],
|
16
18
|
app_identifier: params[:app_identifier],
|
17
19
|
app_version: params[:app_version],
|
18
20
|
build_number: params[:build_number],
|
@@ -23,7 +25,9 @@ module Fastlane
|
|
23
25
|
}
|
24
26
|
validate(platform, options)
|
25
27
|
config = get_config(platform, options)
|
26
|
-
|
28
|
+
client = Shuttle::Client.new(base_url(params[:environment]), params[:api_token])
|
29
|
+
notify(client, platform, config)
|
30
|
+
upload(client, platform, config)
|
27
31
|
|
28
32
|
UI.success("Successfully uploaded to #{params[:app_identifier]} #{params[:app_version]}.#{params[:build_number]} to Shuttle")
|
29
33
|
|
@@ -54,21 +58,31 @@ module Fastlane
|
|
54
58
|
verify_block: proc do |api_token|
|
55
59
|
UI.user_error!("No API token for Shuttle given, pass using `api_token: 'token'`") unless api_token and !api_token.empty?
|
56
60
|
end),
|
57
|
-
FastlaneCore::ConfigItem.new(key: :
|
58
|
-
env_name: "
|
59
|
-
description: "
|
60
|
-
|
61
|
-
|
61
|
+
FastlaneCore::ConfigItem.new(key: :ipa,
|
62
|
+
env_name: "",
|
63
|
+
description: ".ipa file for the build",
|
64
|
+
optional: true,
|
65
|
+
default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]),
|
66
|
+
FastlaneCore::ConfigItem.new(key: :dsym,
|
67
|
+
env_name: "",
|
68
|
+
description: "zipped .dsym package for the build",
|
69
|
+
optional: true,
|
70
|
+
default_value: Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH]),
|
71
|
+
FastlaneCore::ConfigItem.new(key: :apk,
|
72
|
+
env_name: "",
|
73
|
+
description: ".apk file for the build",
|
74
|
+
optional: true,
|
75
|
+
default_value: Actions.lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]),
|
76
|
+
FastlaneCore::ConfigItem.new(key: :mapping,
|
77
|
+
env_name: "",
|
78
|
+
description: "The path to the mapping.txt file",
|
79
|
+
optional: true,
|
80
|
+
default_value: Actions.lane_context[SharedValues::GRADLE_MAPPING_TXT_OUTPUT_PATH]),
|
62
81
|
FastlaneCore::ConfigItem.new(key: :prefix_schema,
|
63
82
|
env_name: "SHUTTLE_PREFIX_SCHEMA",
|
64
83
|
description: "Prefix schema in uploaded app",
|
65
84
|
default_value: Actions.lane_context[SharedValues::PREFIX_SCHEMA],
|
66
85
|
optional: true),
|
67
|
-
FastlaneCore::ConfigItem.new(key: :apk_url,
|
68
|
-
env_name: "SHUTTLE_APK_URL",
|
69
|
-
description: "Url to uploaded apk",
|
70
|
-
default_value: Actions.lane_context[SharedValues::S3_APK_OUTPUT_PATH],
|
71
|
-
optional: true),
|
72
86
|
FastlaneCore::ConfigItem.new(key: :app_identifier,
|
73
87
|
description: "App identifier, either bundle id or package name",
|
74
88
|
type: String,
|
@@ -114,14 +128,14 @@ module Fastlane
|
|
114
128
|
|
115
129
|
def self.validate(platform, params)
|
116
130
|
case platform
|
117
|
-
when :android
|
118
|
-
apk_url = params[:apk_url]
|
119
|
-
UI.user_error!("No apk url given, pass using `apk_url: 'url'` or make sure s3 action succeded and exposed S3_APK_OUTPUT_PATH shared value") unless apk_url and !apk_url.empty?
|
120
131
|
when :ios
|
121
|
-
plist_url = params[:plist_url]
|
122
|
-
UI.user_error!("No plist url given, pass using `plist_url: 'url'` or make sure s3 action succeded and exposed S3_PLIST_OUTPUT_PATH shared value") unless plist_url and !plist_url.empty?
|
123
132
|
url_scheme = params[:prefix_schema]
|
124
133
|
UI.user_error!("No prefix scheme given. Make sure `add_prefix_schema` action succeded before build action") if url_scheme.nil?
|
134
|
+
ipa = params[:ipa]
|
135
|
+
UI.user_error!("No .ipa file path given. Make sure `gym` action succeded") if ipa.nil?
|
136
|
+
when :android
|
137
|
+
apk = params[:apk]
|
138
|
+
UI.user_error!("No .apk file path given. Make sure `gradle` action succeded") if apk.nil?
|
125
139
|
end
|
126
140
|
end
|
127
141
|
|
@@ -135,11 +149,13 @@ module Fastlane
|
|
135
149
|
releaser = params[:releaser] || commit_author
|
136
150
|
|
137
151
|
case platform
|
152
|
+
when :android
|
153
|
+
apk = params[:apk]
|
154
|
+
mapping = params[:mapping]
|
138
155
|
when :ios
|
139
|
-
href = itms_href(params[:plist_url])
|
140
156
|
prefix_schema = params[:prefix_schema]
|
141
|
-
|
142
|
-
|
157
|
+
ipa = params[:ipa]
|
158
|
+
dsym = params[:dsym]
|
143
159
|
end
|
144
160
|
|
145
161
|
{
|
@@ -147,18 +163,20 @@ module Fastlane
|
|
147
163
|
app_identifier: app_identifier,
|
148
164
|
app_version: app_version,
|
149
165
|
build_number: build_number,
|
150
|
-
href: href,
|
151
166
|
release_notes: release_notes,
|
152
167
|
releaser: releaser,
|
153
168
|
binary_size: binary_size,
|
154
169
|
prefix_schema: prefix_schema,
|
155
|
-
environment: params[:environment]
|
170
|
+
environment: params[:environment],
|
171
|
+
ipa: ipa,
|
172
|
+
apk: apk,
|
173
|
+
mapping: mapping,
|
174
|
+
dsym: dsym
|
156
175
|
}
|
157
176
|
end
|
158
177
|
|
159
|
-
def self.notify(platform, params)
|
178
|
+
def self.notify(client, platform, params)
|
160
179
|
build = {
|
161
|
-
href: params[:href],
|
162
180
|
version: params[:app_version],
|
163
181
|
releaseNotes: params[:release_notes],
|
164
182
|
bytes: params[:binary_size],
|
@@ -168,12 +186,40 @@ module Fastlane
|
|
168
186
|
build[:prefixSchema] = params[:prefix_schema] if platform == :ios
|
169
187
|
build[:versionCode] = params[:build_number] if platform == :android
|
170
188
|
|
171
|
-
client = Shuttle::Client.new(base_url(params[:environment]), params[:api_token])
|
172
|
-
|
173
189
|
client.create_build(platform, params[:app_identifier], build)
|
174
190
|
end
|
175
191
|
private_class_method :notify
|
176
192
|
|
193
|
+
def self.upload(client, platform, params)
|
194
|
+
case platform
|
195
|
+
when :ios
|
196
|
+
upload_urls = client.get_upload_urls(platform, params[:app_identifier], params[:prefix_schema])
|
197
|
+
upload_build_url = upload_urls['buildUrl']
|
198
|
+
self.upload_file(upload_build_url, params[:ipa])
|
199
|
+
UI.success("Successfully uploaded ipa file")
|
200
|
+
if params[:dsym]
|
201
|
+
upload_dsym_url = upload_urls['debugFileUrl']
|
202
|
+
self.upload_file(upload_dsym_url, params[:dsym])
|
203
|
+
UI.success("Successfully uploaded dsym file")
|
204
|
+
end
|
205
|
+
when :android
|
206
|
+
upload_urls = client.get_upload_urls(platform, params[:app_identifier], params[:build_number])
|
207
|
+
upload_build_url = upload_urls['buildUrl']
|
208
|
+
self.upload_file(upload_build_url, params[:apk])
|
209
|
+
UI.success("Successfully uploaded apk file")
|
210
|
+
if params[:mapping]
|
211
|
+
upload_mapping_file_url = upload_urls['debugFileUrl']
|
212
|
+
self.upload_file(upload_mapping_file_url, params[:mapping])
|
213
|
+
UI.success("Successfully uploaded mapping file")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.upload_file(url, build)
|
219
|
+
client = S3::Client.new
|
220
|
+
client.upload_file(url, build)
|
221
|
+
end
|
222
|
+
|
177
223
|
def self.base_url(environment)
|
178
224
|
case environment
|
179
225
|
when :production
|
@@ -184,11 +230,6 @@ module Fastlane
|
|
184
230
|
end
|
185
231
|
private_class_method :base_url
|
186
232
|
|
187
|
-
def self.itms_href(plist_url)
|
188
|
-
"itms-services://?action=download-manifest&url=#{URI.encode_www_form_component(plist_url)}"
|
189
|
-
end
|
190
|
-
private_class_method :itms_href
|
191
|
-
|
192
233
|
def self.commit_author
|
193
234
|
sh("git --no-pager show -s --format='%ae'", print_command: false, print_command_output: false).strip
|
194
235
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module S3
|
6
|
+
class Client
|
7
|
+
def upload_file(url, file)
|
8
|
+
retry_options = {
|
9
|
+
max: 2,
|
10
|
+
interval: 0.05,
|
11
|
+
interval_randomness: 0.5,
|
12
|
+
backoff_factor: 2
|
13
|
+
}
|
14
|
+
connection = Faraday.new(
|
15
|
+
url
|
16
|
+
) do |conn|
|
17
|
+
conn.request :retry, retry_options
|
18
|
+
conn.request :multipart
|
19
|
+
conn.response :raise_error
|
20
|
+
conn.adapter :net_http
|
21
|
+
end
|
22
|
+
|
23
|
+
connection.put(
|
24
|
+
'',
|
25
|
+
File.read(file)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -21,19 +21,25 @@ module Fastlane
|
|
21
21
|
) do |conn|
|
22
22
|
conn.request :retry, retry_options
|
23
23
|
conn.request :multipart
|
24
|
-
|
25
24
|
conn.response :raise_error
|
26
|
-
|
25
|
+
conn.response :json
|
27
26
|
conn.adapter :net_http
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def create_build(platform, app_identifier, build)
|
32
31
|
@conn.post(
|
33
|
-
"cd/apps/#{platform}/#{app_identifier}/builds",
|
32
|
+
"cd/apps/#{platform}/#{app_identifier}/builds/v2",
|
34
33
|
{ build: build }.to_json
|
35
34
|
)
|
36
35
|
end
|
36
|
+
|
37
|
+
def get_upload_urls(platform, app_id, build_identifier)
|
38
|
+
response = @conn.get(
|
39
|
+
"projects/apps/#{platform}/#{app_id}/builds/#{build_identifier}/upload-url/v2"
|
40
|
+
)
|
41
|
+
return response.body
|
42
|
+
end
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-polidea
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotrek Dubiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.17.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.17.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: plist
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,16 +230,16 @@ dependencies:
|
|
230
230
|
name: simplecov
|
231
231
|
requirement: !ruby/object:Gem::Requirement
|
232
232
|
requirements:
|
233
|
-
- -
|
233
|
+
- - '='
|
234
234
|
- !ruby/object:Gem::Version
|
235
|
-
version: '0'
|
235
|
+
version: '0.17'
|
236
236
|
type: :development
|
237
237
|
prerelease: false
|
238
238
|
version_requirements: !ruby/object:Gem::Requirement
|
239
239
|
requirements:
|
240
|
-
- -
|
240
|
+
- - '='
|
241
241
|
- !ruby/object:Gem::Version
|
242
|
-
version: '0'
|
242
|
+
version: '0.17'
|
243
243
|
- !ruby/object:Gem::Dependency
|
244
244
|
name: fastlane
|
245
245
|
requirement: !ruby/object:Gem::Requirement
|
@@ -265,8 +265,6 @@ files:
|
|
265
265
|
- lib/fastlane/plugin/polidea.rb
|
266
266
|
- lib/fastlane/plugin/polidea/actions/add_prefix_schema.rb
|
267
267
|
- lib/fastlane/plugin/polidea/actions/extract_app_info.rb
|
268
|
-
- lib/fastlane/plugin/polidea/actions/fota_mail.rb
|
269
|
-
- lib/fastlane/plugin/polidea/actions/fota_s3.rb
|
270
268
|
- lib/fastlane/plugin/polidea/actions/import_provisioning.rb
|
271
269
|
- lib/fastlane/plugin/polidea/actions/release_notes.rb
|
272
270
|
- lib/fastlane/plugin/polidea/actions/release_notes_from_commits.rb
|
@@ -275,6 +273,7 @@ files:
|
|
275
273
|
- lib/fastlane/plugin/polidea/helper/mime.rb
|
276
274
|
- lib/fastlane/plugin/polidea/helper/page_generator.rb
|
277
275
|
- lib/fastlane/plugin/polidea/helper/qr_generator.rb
|
276
|
+
- lib/fastlane/plugin/polidea/helper/s3.rb
|
278
277
|
- lib/fastlane/plugin/polidea/helper/shuttle.rb
|
279
278
|
- lib/fastlane/plugin/polidea/version.rb
|
280
279
|
- templates/install.erb
|
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'redcarpet'
|
2
|
-
require 'fastlane/erb_template_helper'
|
3
|
-
|
4
|
-
module Fastlane
|
5
|
-
module Actions
|
6
|
-
class FotaMailAction < Action
|
7
|
-
def self.is_supported?(platform)
|
8
|
-
true
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.run(options)
|
12
|
-
Fastlane::Polidea.session.action_launched("fota_mail", options)
|
13
|
-
|
14
|
-
Actions.verify_gem!('premailer')
|
15
|
-
require 'premailer'
|
16
|
-
inline_images(options)
|
17
|
-
mailgunit(options)
|
18
|
-
|
19
|
-
Fastlane::Polidea.session.action_completed("fota_mail")
|
20
|
-
UI.success "Mail sent!"
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.description
|
24
|
-
"Send a success/error message to an email group"
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.available_options
|
28
|
-
[
|
29
|
-
FastlaneCore::ConfigItem.new(key: :postmaster,
|
30
|
-
env_name: "MAILGUN_SANDBOX_POSTMASTER",
|
31
|
-
description: "Mailgun sandbox domain postmaster for your mail"),
|
32
|
-
FastlaneCore::ConfigItem.new(key: :apikey,
|
33
|
-
env_name: "MAILGUN_APIKEY",
|
34
|
-
description: "Mailgun apikey for your mail"),
|
35
|
-
FastlaneCore::ConfigItem.new(key: :to,
|
36
|
-
env_name: "MAILGUN_TO",
|
37
|
-
description: "Destination of your mail"),
|
38
|
-
FastlaneCore::ConfigItem.new(key: :from,
|
39
|
-
env_name: "MAILGUN_FROM",
|
40
|
-
optional: true,
|
41
|
-
description: "Mailgun sender name",
|
42
|
-
default_value: "Polidea"),
|
43
|
-
FastlaneCore::ConfigItem.new(key: :success,
|
44
|
-
env_name: "MAILGUN_SUCCESS",
|
45
|
-
description: "Was this build successful? (true/false)",
|
46
|
-
optional: true,
|
47
|
-
default_value: true,
|
48
|
-
is_string: false),
|
49
|
-
FastlaneCore::ConfigItem.new(key: :ci_build_link,
|
50
|
-
env_name: "MAILGUN_CI_BUILD_LINK",
|
51
|
-
description: "CI Build Link",
|
52
|
-
optional: true,
|
53
|
-
is_string: true),
|
54
|
-
FastlaneCore::ConfigItem.new(key: :template_path,
|
55
|
-
env_name: "MAILGUN_TEMPLATE_PATH",
|
56
|
-
description: "Mail HTML template",
|
57
|
-
optional: true,
|
58
|
-
is_string: true),
|
59
|
-
FastlaneCore::ConfigItem.new(key: :platform,
|
60
|
-
env_name: "MAILGUN_PLATFORM",
|
61
|
-
description: "Platform used in mail template",
|
62
|
-
optional: true,
|
63
|
-
default_value: Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]),
|
64
|
-
FastlaneCore::ConfigItem.new(key: :app_icon,
|
65
|
-
env_name: "MAILGUN_APP_ICON",
|
66
|
-
description: "Path to app icon file",
|
67
|
-
is_string: true,
|
68
|
-
optional: true,
|
69
|
-
default_value: Actions.lane_context[SharedValues::ICON_OUTPUT_PATH]),
|
70
|
-
FastlaneCore::ConfigItem.new(key: :app_name,
|
71
|
-
env_name: "MAILGUN_APP_NAME",
|
72
|
-
description: "Application name",
|
73
|
-
is_string: true,
|
74
|
-
default_value: Actions.lane_context[SharedValues::APP_NAME]),
|
75
|
-
FastlaneCore::ConfigItem.new(key: :app_version,
|
76
|
-
env_name: "MAILGUN_APP_VERSION",
|
77
|
-
description: "Application version",
|
78
|
-
is_string: true,
|
79
|
-
default_value: Actions.lane_context[SharedValues::APP_VERSION]),
|
80
|
-
FastlaneCore::ConfigItem.new(key: :build_number,
|
81
|
-
env_name: "MAILGUN_BUILD_NUMBER",
|
82
|
-
description: "Build number",
|
83
|
-
default_value: Actions.lane_context[SharedValues::BUILD_NUMBER]),
|
84
|
-
FastlaneCore::ConfigItem.new(key: :installation_link,
|
85
|
-
env_name: "MAILGUN_INSTALLATION_LINK",
|
86
|
-
description: "Link to installation page",
|
87
|
-
is_string: true,
|
88
|
-
default_value: Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH]),
|
89
|
-
FastlaneCore::ConfigItem.new(key: :release_notes,
|
90
|
-
env_name: "MAILGUN_RELEASE_NOTES",
|
91
|
-
description: "Release notes",
|
92
|
-
type: String,
|
93
|
-
optional: true,
|
94
|
-
default_value: Actions.lane_context[SharedValues::RELEASE_NOTES]),
|
95
|
-
FastlaneCore::ConfigItem.new(key: :binary_size,
|
96
|
-
env_name: "MAILGUN_BINARY_SIZE",
|
97
|
-
description: "Binary size",
|
98
|
-
type: Integer,
|
99
|
-
default_value: Actions.lane_context[SharedValues::BINARY_SIZE]),
|
100
|
-
FastlaneCore::ConfigItem.new(key: :inline,
|
101
|
-
type: Array,
|
102
|
-
optional: true,
|
103
|
-
default_value: [])
|
104
|
-
]
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.author
|
108
|
-
"thiagolioy"
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.inline_images(options)
|
112
|
-
options[:inline] = [
|
113
|
-
qr_code(options[:installation_link])
|
114
|
-
]
|
115
|
-
options[:inline] << File.new(options[:app_icon]) if options[:app_icon]
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.qr_code(installation_link)
|
119
|
-
qr_code_path = "/tmp/qr_code.png"
|
120
|
-
QRGenerator.new(installation_link, ::ChunkyPNG::Color.rgb(21, 18, 126)).generate(qr_code_path)
|
121
|
-
File.new(qr_code_path)
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.mailgunit(options)
|
125
|
-
sandbox_domain = options[:postmaster].split("@").last
|
126
|
-
body = mail_template(options)
|
127
|
-
|
128
|
-
sh """curl -s --user 'api:#{options[:apikey]}' \
|
129
|
-
https://api.mailgun.net/v3/#{sandbox_domain}/messages \
|
130
|
-
-F from='#{options[:from]} <#{options[:postmaster]}>' \
|
131
|
-
-F to='#{options[:to]}' \
|
132
|
-
-F subject='#{options[:app_name]} #{options[:app_version]} (#{options[:build_number]}) for #{human_platform(options[:platform])} is ready to install' \
|
133
|
-
--form-string html=#{Shellwords.escape(body)} \ """ + options[:inline].map { |file| "-F inline=@#{file.path}" }.join(" "), print_command: false, print_command_output: false
|
134
|
-
|
135
|
-
return body
|
136
|
-
end
|
137
|
-
|
138
|
-
def self.mail_template(options)
|
139
|
-
hash = {
|
140
|
-
author: Actions.git_author_email,
|
141
|
-
last_commit: Actions.last_git_commit_message,
|
142
|
-
is_android: options[:platform] == :android,
|
143
|
-
app_icon: options[:app_icon] ? File.basename(options[:app_icon]) : nil,
|
144
|
-
app_name: options[:app_name],
|
145
|
-
app_version: options[:app_version],
|
146
|
-
build_number: options[:build_number],
|
147
|
-
installation_link: options[:installation_link],
|
148
|
-
release_notes: options[:release_notes],
|
149
|
-
platform: options[:platform],
|
150
|
-
release_date: DateTime.now.strftime('%b %d, %Y'),
|
151
|
-
binary_size: (options[:binary_size] / 1024.0 / 1024.0).round(2).to_s,
|
152
|
-
qr_code: "qr_code.png"
|
153
|
-
}
|
154
|
-
hash[:success] = options[:success]
|
155
|
-
hash[:ci_build_link] = options[:ci_build_link]
|
156
|
-
|
157
|
-
# create html from template
|
158
|
-
html_template_path = options[:template_path]
|
159
|
-
if html_template_path && File.exist?(html_template_path)
|
160
|
-
eth = Fastlane::ErbTemplateHelper
|
161
|
-
html_template = eth.load_from_path(html_template_path)
|
162
|
-
mail_html = eth.render(html_template, hash)
|
163
|
-
else
|
164
|
-
mail_html = PageGenerator.mail(hash)
|
165
|
-
end
|
166
|
-
|
167
|
-
premailer = Premailer.new(
|
168
|
-
mail_html,
|
169
|
-
{ warn_level: Premailer::Warnings::SAFE, with_html_string: true }
|
170
|
-
)
|
171
|
-
premailer.to_inline_css
|
172
|
-
end
|
173
|
-
|
174
|
-
def self.human_platform(platform)
|
175
|
-
case platform
|
176
|
-
when :ios
|
177
|
-
"iOS"
|
178
|
-
when :android
|
179
|
-
"Android"
|
180
|
-
else
|
181
|
-
platform.to_s
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
# rubocop:enable Metrics/MethodLength
|
@@ -1,568 +0,0 @@
|
|
1
|
-
# rubocop:disable Metrics/AbcSize
|
2
|
-
# rubocop:disable Metrics/ClassLength
|
3
|
-
require 'fastlane/erb_template_helper'
|
4
|
-
require 'ostruct'
|
5
|
-
require 'securerandom'
|
6
|
-
|
7
|
-
module Fastlane
|
8
|
-
module Actions
|
9
|
-
module SharedValues
|
10
|
-
S3_IPA_OUTPUT_PATH = :S3_IPA_OUTPUT_PATH
|
11
|
-
S3_DSYM_OUTPUT_PATH = :S3_DSYM_OUTPUT_PATH
|
12
|
-
S3_PLIST_OUTPUT_PATH = :S3_PLIST_OUTPUT_PATH
|
13
|
-
S3_APK_OUTPUT_PATH = :S3_APK_OUTPUT_PATH
|
14
|
-
S3_MAPPING_OUTPUT_PATH = :S3_MAPPING_OUTPUT_PATH
|
15
|
-
S3_HTML_OUTPUT_PATH = :S3_HTML_OUTPUT_PATH
|
16
|
-
S3_VERSION_OUTPUT_PATH = :S3_VERSION_OUTPUT_PATH
|
17
|
-
S3_ICON_OUTPUT_PATH = :S3_ICON_OUTPUT_PATH
|
18
|
-
end
|
19
|
-
|
20
|
-
class FotaS3Action < Action
|
21
|
-
def self.run(config)
|
22
|
-
Fastlane::Polidea.session.action_launched("fota_s3", config)
|
23
|
-
|
24
|
-
platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME].to_sym
|
25
|
-
|
26
|
-
# Calling fetch on config so that default values will be used
|
27
|
-
params = {}
|
28
|
-
params[:ipa] = config[:ipa]
|
29
|
-
params[:apk] = config[:apk]
|
30
|
-
params[:icon] = config[:icon]
|
31
|
-
params[:dsym] = config[:dsym]
|
32
|
-
params[:mapping] = config[:mapping]
|
33
|
-
params[:access_key] = config[:access_key]
|
34
|
-
params[:secret_access_key] = config[:secret_access_key]
|
35
|
-
params[:bucket] = config[:bucket]
|
36
|
-
params[:region] = config[:region]
|
37
|
-
params[:acl] = config[:acl]
|
38
|
-
params[:upload_metadata] = config[:upload_metadata]
|
39
|
-
params[:plist_template_path] = config[:plist_template_path]
|
40
|
-
params[:html_template_path] = config[:html_template_path]
|
41
|
-
params[:html_file_name] = config[:html_file_name]
|
42
|
-
params[:version_template_path] = config[:version_template_path]
|
43
|
-
params[:version_file_name] = config[:version_file_name]
|
44
|
-
params[:acl] = config[:acl]
|
45
|
-
params[:release_notes] = config[:release_notes]
|
46
|
-
params[:treat_bucket_as_domain_name] = config[:treat_bucket_as_domain_name]
|
47
|
-
|
48
|
-
case platform
|
49
|
-
when :ios
|
50
|
-
upload_ios(params)
|
51
|
-
when :android
|
52
|
-
upload_android(params)
|
53
|
-
end
|
54
|
-
|
55
|
-
Fastlane::Polidea.session.action_completed("fota_s3")
|
56
|
-
return true
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.upload_ios(params)
|
60
|
-
# Pulling parameters for other uses
|
61
|
-
s3_region = params[:region]
|
62
|
-
s3_subdomain = params[:region] ? "s3-#{params[:region]}" : "s3"
|
63
|
-
s3_access_key = params[:access_key]
|
64
|
-
s3_secret_access_key = params[:secret_access_key]
|
65
|
-
s3_bucket = params[:bucket]
|
66
|
-
ipa_file = params[:ipa]
|
67
|
-
icon_file = params[:icon]
|
68
|
-
dsym_file = params[:dsym]
|
69
|
-
acl = params[:acl]
|
70
|
-
release_notes = params[:release_notes]
|
71
|
-
treat_bucket_as_domain_name = params[:treat_bucket_as_domain_name]
|
72
|
-
|
73
|
-
validate(params)
|
74
|
-
UI.user_error!("No IPA file path given, pass using `ipa: 'ipa path'`") unless ipa_file.to_s.length > 0
|
75
|
-
|
76
|
-
UI.message("Will transform S3 urls from https://s3.amazonaws.com/#{s3_bucket} to https://#{s3_bucket}") if treat_bucket_as_domain_name
|
77
|
-
|
78
|
-
bucket = get_bucket(s3_access_key, s3_secret_access_key, s3_region, s3_bucket)
|
79
|
-
|
80
|
-
# Gets info used for the plist
|
81
|
-
info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa_file)
|
82
|
-
|
83
|
-
build_number = info['CFBundleVersion']
|
84
|
-
bundle_id = info['CFBundleIdentifier']
|
85
|
-
bundle_version = info['CFBundleShortVersionString']
|
86
|
-
app_name = info['CFBundleDisplayName'] || info['CFBundleName']
|
87
|
-
full_version = "#{bundle_version}.#{build_number}"
|
88
|
-
url_part = get_url_part(app_name, "ios", bundle_version, build_number)
|
89
|
-
|
90
|
-
plist_template_path = params[:plist_template_path]
|
91
|
-
html_file_name = params[:html_file_name]
|
92
|
-
version_template_path = params[:version_template_path]
|
93
|
-
version_file_name = params[:version_file_name]
|
94
|
-
|
95
|
-
ipa_file_basename = File.basename(ipa_file)
|
96
|
-
ipa_file_name = "#{url_part}#{ipa_file_basename}"
|
97
|
-
ipa_file_data = File.open(ipa_file, 'rb')
|
98
|
-
|
99
|
-
ipa_url = self.upload_file(bucket, ipa_file_name, ipa_file_data, acl, treat_bucket_as_domain_name)
|
100
|
-
|
101
|
-
# Setting action and environment variables
|
102
|
-
Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH] = ipa_url
|
103
|
-
ENV[SharedValues::S3_IPA_OUTPUT_PATH.to_s] = ipa_url
|
104
|
-
|
105
|
-
if dsym_file
|
106
|
-
dsym_file_basename = File.basename(dsym_file)
|
107
|
-
dsym_file_name = "#{url_part}#{dsym_file_basename}"
|
108
|
-
dsym_file_data = File.open(dsym_file, 'rb')
|
109
|
-
|
110
|
-
dsym_url = self.upload_file(bucket, dsym_file_name, dsym_file_data, acl, treat_bucket_as_domain_name)
|
111
|
-
|
112
|
-
dsym_file_data.close
|
113
|
-
end
|
114
|
-
|
115
|
-
if params[:upload_metadata] == false
|
116
|
-
return true
|
117
|
-
end
|
118
|
-
|
119
|
-
#####################################
|
120
|
-
#
|
121
|
-
# html and plist building
|
122
|
-
#
|
123
|
-
#####################################
|
124
|
-
|
125
|
-
# Creating plist and html names
|
126
|
-
plist_file_name = "#{url_part}manifest.plist"
|
127
|
-
plist_url = "https://#{s3_subdomain}.amazonaws.com/#{s3_bucket}/#{plist_file_name}"
|
128
|
-
|
129
|
-
html_file_name ||= "#{url_part}index.html"
|
130
|
-
html_resources_name = "#{url_part}installation-page"
|
131
|
-
|
132
|
-
version_file_name ||= "#{url_part}version.json"
|
133
|
-
|
134
|
-
# grabs module
|
135
|
-
eth = Fastlane::ErbTemplateHelper
|
136
|
-
|
137
|
-
# Creates plist from template
|
138
|
-
if plist_template_path && File.exist?(plist_template_path)
|
139
|
-
plist_template = eth.load_from_path(plist_template_path)
|
140
|
-
else
|
141
|
-
plist_template = eth.load("s3_plist_template")
|
142
|
-
end
|
143
|
-
plist_render = eth.render(plist_template, {
|
144
|
-
url: ipa_url,
|
145
|
-
ipa_url: ipa_url,
|
146
|
-
bundle_id: bundle_id,
|
147
|
-
build_number: build_number,
|
148
|
-
bundle_version: bundle_version,
|
149
|
-
title: app_name
|
150
|
-
})
|
151
|
-
|
152
|
-
# Gets icon from ipa and uploads it
|
153
|
-
icon_url = self.upload_icon(icon_file, url_part, bucket, acl, treat_bucket_as_domain_name)
|
154
|
-
|
155
|
-
# Creates html from template
|
156
|
-
html_render = PageGenerator.installation_page({
|
157
|
-
url: "itms-services://?action=download-manifest&url=#{URI.encode_www_form_component(plist_url)}",
|
158
|
-
app_version: bundle_version,
|
159
|
-
build_number: build_number,
|
160
|
-
app_name: app_name,
|
161
|
-
app_icon: icon_url,
|
162
|
-
platform: "ios",
|
163
|
-
release_notes: release_notes
|
164
|
-
})
|
165
|
-
|
166
|
-
# Creates version from template
|
167
|
-
if version_template_path && File.exist?(version_template_path)
|
168
|
-
version_template = eth.load_from_path(version_template_path)
|
169
|
-
else
|
170
|
-
version_template = eth.load("s3_version_template")
|
171
|
-
end
|
172
|
-
version_render = eth.render(version_template, {
|
173
|
-
url: plist_url,
|
174
|
-
plist_url: plist_url,
|
175
|
-
ipa_url: ipa_url,
|
176
|
-
build_number: build_number,
|
177
|
-
bundle_version: bundle_version,
|
178
|
-
full_version: full_version
|
179
|
-
})
|
180
|
-
|
181
|
-
#####################################
|
182
|
-
#
|
183
|
-
# html and plist uploading
|
184
|
-
#
|
185
|
-
#####################################
|
186
|
-
|
187
|
-
plist_url = self.upload_file(bucket, plist_file_name, plist_render, acl, treat_bucket_as_domain_name)
|
188
|
-
html_url = self.upload_file(bucket, html_file_name, html_render, acl, treat_bucket_as_domain_name)
|
189
|
-
self.upload_directory(bucket, html_resources_name, "#{__dir__}/../templates/installation-page", acl)
|
190
|
-
version_url = self.upload_file(bucket, version_file_name, version_render, acl, treat_bucket_as_domain_name)
|
191
|
-
|
192
|
-
# Setting action and environment variables
|
193
|
-
Actions.lane_context[SharedValues::S3_PLIST_OUTPUT_PATH] = plist_url
|
194
|
-
ENV[SharedValues::S3_PLIST_OUTPUT_PATH.to_s] = plist_url
|
195
|
-
|
196
|
-
Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH] = html_url
|
197
|
-
ENV[SharedValues::S3_HTML_OUTPUT_PATH.to_s] = html_url
|
198
|
-
|
199
|
-
Actions.lane_context[SharedValues::S3_VERSION_OUTPUT_PATH] = version_url
|
200
|
-
ENV[SharedValues::S3_VERSION_OUTPUT_PATH.to_s] = version_url
|
201
|
-
|
202
|
-
UI.success("Successfully uploaded ipa file to '#{Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH]}'")
|
203
|
-
UI.success("Successfully uploaded plist file to '#{Actions.lane_context[SharedValues::S3_PLIST_OUTPUT_PATH]}'")
|
204
|
-
UI.success("Successfully uploaded html file to '#{Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH]}'")
|
205
|
-
UI.success("Successfully uploaded version file to '#{Actions.lane_context[SharedValues::S3_VERSION_OUTPUT_PATH]}'")
|
206
|
-
|
207
|
-
if icon_url
|
208
|
-
Actions.lane_context[SharedValues::S3_ICON_OUTPUT_PATH] = icon_url
|
209
|
-
ENV[SharedValues::S3_ICON_OUTPUT_PATH.to_s] = icon_url
|
210
|
-
UI.success("Successfully uploaded icon file to '#{Actions.lane_context[SharedValues::S3_ICON_OUTPUT_PATH]}'")
|
211
|
-
end
|
212
|
-
if dsym_url
|
213
|
-
Actions.lane_context[SharedValues::S3_DSYM_OUTPUT_PATH] = dsym_url
|
214
|
-
ENV[SharedValues::S3_DSYM_OUTPUT_PATH.to_s] = dsym_url
|
215
|
-
UI.success("Successfully uploaded dsym file to '#{Actions.lane_context[SharedValues::S3_DSYM_OUTPUT_PATH]}'")
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
def self.upload_android(params)
|
220
|
-
# Pulling parameters for other uses
|
221
|
-
s3_region = params[:region]
|
222
|
-
s3_access_key = params[:access_key]
|
223
|
-
s3_secret_access_key = params[:secret_access_key]
|
224
|
-
s3_bucket = params[:bucket]
|
225
|
-
apk_file = params[:apk]
|
226
|
-
icon_file = params[:icon]
|
227
|
-
mapping_file = params[:mapping]
|
228
|
-
acl = params[:acl]
|
229
|
-
release_notes = params[:release_notes]
|
230
|
-
treat_bucket_as_domain_name = params[:treat_bucket_as_domain_name]
|
231
|
-
|
232
|
-
validate(params)
|
233
|
-
UI.user_error!("No APK file path given, pass using `apk: 'apk path'`") unless apk_file.to_s.length > 0
|
234
|
-
|
235
|
-
UI.message("Will transform S3 urls from https://s3.amazonaws.com/#{s3_bucket} to https://#{s3_bucket}") if treat_bucket_as_domain_name
|
236
|
-
|
237
|
-
bucket = get_bucket(s3_access_key, s3_secret_access_key, s3_region, s3_bucket)
|
238
|
-
|
239
|
-
# Gets info used from the apk manifest
|
240
|
-
manifest = Android::Apk.new(apk_file).manifest
|
241
|
-
|
242
|
-
app_name = manifest.label
|
243
|
-
build_number = manifest.version_code
|
244
|
-
app_version = manifest.version_name
|
245
|
-
url_part = get_url_part(app_name, "android", app_version, build_number)
|
246
|
-
|
247
|
-
html_file_name = params[:html_file_name]
|
248
|
-
|
249
|
-
apk_file_basename = File.basename(apk_file)
|
250
|
-
apk_file_name = "#{url_part}#{apk_file_basename}"
|
251
|
-
apk_file_data = File.open(apk_file, 'rb')
|
252
|
-
|
253
|
-
apk_url = self.upload_file(bucket, apk_file_name, apk_file_data, acl, treat_bucket_as_domain_name)
|
254
|
-
|
255
|
-
# Setting action and environment variables
|
256
|
-
Actions.lane_context[SharedValues::S3_APK_OUTPUT_PATH] = apk_url
|
257
|
-
ENV[SharedValues::S3_APK_OUTPUT_PATH.to_s] = apk_url
|
258
|
-
|
259
|
-
if mapping_file
|
260
|
-
mapping_file_basename = File.basename(mapping_file)
|
261
|
-
mapping_file_name = "#{url_part}#{mapping_file_basename}"
|
262
|
-
mapping_file_data = File.open(mapping_file, 'rb')
|
263
|
-
|
264
|
-
mapping_url = self.upload_file(bucket, mapping_file_name, mapping_file_data, acl, treat_bucket_as_domain_name)
|
265
|
-
|
266
|
-
# Setting action and environment variables
|
267
|
-
Actions.lane_context[SharedValues::S3_MAPPING_OUTPUT_PATH] = mapping_url
|
268
|
-
ENV[SharedValues::S3_MAPPING_OUTPUT_PATH.to_s] = mapping_url
|
269
|
-
|
270
|
-
mapping_file_data.close
|
271
|
-
end
|
272
|
-
|
273
|
-
#####################################
|
274
|
-
#
|
275
|
-
# html building
|
276
|
-
#
|
277
|
-
#####################################
|
278
|
-
|
279
|
-
# Creating html names
|
280
|
-
|
281
|
-
html_file_name ||= "#{url_part}index.html"
|
282
|
-
html_resources_name = "#{url_part}installation-page"
|
283
|
-
|
284
|
-
# Gets icon from ipa and uploads it
|
285
|
-
icon_url = self.upload_icon(icon_file, url_part, bucket, acl, treat_bucket_as_domain_name)
|
286
|
-
|
287
|
-
# Creates html from template
|
288
|
-
html_render = PageGenerator.installation_page({
|
289
|
-
url: apk_url,
|
290
|
-
app_version: app_version,
|
291
|
-
build_number: build_number,
|
292
|
-
app_name: app_name,
|
293
|
-
app_icon: icon_url,
|
294
|
-
platform: "android",
|
295
|
-
release_notes: release_notes
|
296
|
-
})
|
297
|
-
|
298
|
-
html_url = self.upload_file(bucket, html_file_name, html_render, acl, treat_bucket_as_domain_name)
|
299
|
-
self.upload_directory(bucket, html_resources_name, "#{__dir__}/../templates/installation-page", acl)
|
300
|
-
|
301
|
-
Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH] = html_url
|
302
|
-
ENV[SharedValues::S3_HTML_OUTPUT_PATH.to_s] = html_url
|
303
|
-
|
304
|
-
UI.success("Successfully uploaded apk file to '#{Actions.lane_context[SharedValues::S3_APK_OUTPUT_PATH]}'")
|
305
|
-
UI.success("Successfully uploaded html file to '#{Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH]}'")
|
306
|
-
|
307
|
-
if icon_url
|
308
|
-
Actions.lane_context[SharedValues::S3_ICON_OUTPUT_PATH] = icon_url
|
309
|
-
ENV[SharedValues::S3_ICON_OUTPUT_PATH.to_s] = icon_url
|
310
|
-
UI.success("Successfully uploaded icon file to '#{Actions.lane_context[SharedValues::S3_ICON_OUTPUT_PATH]}'")
|
311
|
-
end
|
312
|
-
if mapping_url
|
313
|
-
UI.success("Successfully uploaded mapping file to '#{Actions.lane_context[SharedValues::S3_MAPPING_OUTPUT_PATH]}'")
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
def self.validate(params)
|
318
|
-
s3_access_key = params[:access_key]
|
319
|
-
s3_secret_access_key = params[:secret_access_key]
|
320
|
-
s3_bucket = params[:bucket]
|
321
|
-
|
322
|
-
UI.user_error!("No S3 access key given, pass using `access_key: 'key'`") unless s3_access_key.to_s.length > 0
|
323
|
-
UI.user_error!("No S3 secret access key given, pass using `secret_access_key: 'secret key'`") unless s3_secret_access_key.to_s.length > 0
|
324
|
-
UI.user_error!("No S3 bucket given, pass using `bucket: 'bucket'`") unless s3_bucket.to_s.length > 0
|
325
|
-
end
|
326
|
-
|
327
|
-
def self.get_url_part(app_name, platform, app_version, build_number)
|
328
|
-
random_part = SecureRandom.hex(10)
|
329
|
-
"#{app_name}/#{platform}/#{app_version}_#{build_number}/#{random_part}/"
|
330
|
-
end
|
331
|
-
|
332
|
-
def self.get_bucket(s3_access_key, s3_secret_access_key, s3_region, s3_bucket)
|
333
|
-
self.s3_client(s3_access_key, s3_secret_access_key, s3_region).bucket(s3_bucket)
|
334
|
-
end
|
335
|
-
|
336
|
-
def self.s3_client(s3_access_key, s3_secret_access_key, s3_region)
|
337
|
-
Actions.verify_gem!('aws-sdk-s3')
|
338
|
-
require 'aws-sdk-s3'
|
339
|
-
|
340
|
-
if s3_region
|
341
|
-
s3_client = Aws::S3::Resource.new(
|
342
|
-
access_key_id: s3_access_key,
|
343
|
-
secret_access_key: s3_secret_access_key,
|
344
|
-
region: s3_region
|
345
|
-
)
|
346
|
-
else
|
347
|
-
s3_client = Aws::S3::Resource.new(
|
348
|
-
access_key_id: s3_access_key,
|
349
|
-
secret_access_key: s3_secret_access_key
|
350
|
-
)
|
351
|
-
end
|
352
|
-
s3_client
|
353
|
-
end
|
354
|
-
|
355
|
-
def self.upload_file(bucket, file_name, file_data, acl, treat_bucket_as_domain_name)
|
356
|
-
obj = bucket.put_object({
|
357
|
-
key: file_name,
|
358
|
-
body: file_data,
|
359
|
-
acl: acl,
|
360
|
-
content_type: Mime.content_type_for_file(file_name)
|
361
|
-
})
|
362
|
-
|
363
|
-
# When you enable versioning on a S3 bucket,
|
364
|
-
# writing to an object will create an object version
|
365
|
-
# instead of replacing the existing object.
|
366
|
-
# http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/ObjectVersion.html
|
367
|
-
if obj.kind_of? Aws::S3::ObjectVersion
|
368
|
-
obj = obj.object
|
369
|
-
end
|
370
|
-
|
371
|
-
if treat_bucket_as_domain_name
|
372
|
-
# Return public url
|
373
|
-
shorten_url(obj.public_url.to_s)
|
374
|
-
else
|
375
|
-
obj.public_url.to_s
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
def self.upload_directory(bucket, directory_name, directory_path, acl)
|
380
|
-
files = files_at_path(directory_path)
|
381
|
-
|
382
|
-
files.each do |file|
|
383
|
-
local_path = directory_path + file
|
384
|
-
s3_path = directory_name + file
|
385
|
-
|
386
|
-
bucket.put_object({
|
387
|
-
key: s3_path,
|
388
|
-
body: File.open(local_path),
|
389
|
-
acl: acl,
|
390
|
-
content_type: Mime.content_type_for_file(local_path)
|
391
|
-
})
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
def self.files_at_path(path)
|
396
|
-
files = Dir.glob(path + "/**/*")
|
397
|
-
to_remove = []
|
398
|
-
files.each do |file|
|
399
|
-
if File.directory?(file)
|
400
|
-
to_remove.push file
|
401
|
-
else
|
402
|
-
file.slice! path
|
403
|
-
end
|
404
|
-
end
|
405
|
-
to_remove.each do |file|
|
406
|
-
files.delete file
|
407
|
-
end
|
408
|
-
return files
|
409
|
-
end
|
410
|
-
|
411
|
-
#
|
412
|
-
# NOT a fan of this as this was taken straight from Shenzhen
|
413
|
-
# https://github.com/nomad/shenzhen/blob/986792db5d4d16a80c865a2748ee96ba63644821/lib/shenzhen/plugins/s3.rb#L32
|
414
|
-
#
|
415
|
-
# Need to find a way to not use this copied method
|
416
|
-
#
|
417
|
-
# AGAIN, I am not happy about this right now.
|
418
|
-
# Using this for prototype reasons.
|
419
|
-
#
|
420
|
-
def self.expand_path_with_substitutions_from_ipa_plist(ipa, path)
|
421
|
-
substitutions = path.scan(/\{CFBundle[^}]+\}/)
|
422
|
-
return path if substitutions.empty?
|
423
|
-
info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa) or return path
|
424
|
-
|
425
|
-
substitutions.uniq.each do |substitution|
|
426
|
-
key = substitution[1...-1]
|
427
|
-
value = info[key]
|
428
|
-
path.gsub!(Regexp.new(substitution), value) if value
|
429
|
-
end
|
430
|
-
|
431
|
-
return path
|
432
|
-
end
|
433
|
-
|
434
|
-
def self.upload_icon(icon_path, url_part, bucket, acl, treat_bucket_as_domain_name)
|
435
|
-
return unless icon_path
|
436
|
-
icon_file_basename = File.basename(icon_path)
|
437
|
-
icon_file = File.open(icon_path)
|
438
|
-
icon_file_name = "#{url_part}#{icon_file_basename}"
|
439
|
-
self.upload_file(bucket, icon_file_name, icon_file, acl, treat_bucket_as_domain_name)
|
440
|
-
end
|
441
|
-
|
442
|
-
def self.shorten_url(url)
|
443
|
-
uri = URI.parse(url)
|
444
|
-
uri.scheme + ':/' + uri.path
|
445
|
-
end
|
446
|
-
|
447
|
-
def self.description
|
448
|
-
"Generates a plist file and uploads all to AWS S3"
|
449
|
-
end
|
450
|
-
|
451
|
-
def self.available_options
|
452
|
-
[
|
453
|
-
FastlaneCore::ConfigItem.new(key: :ipa,
|
454
|
-
env_name: "",
|
455
|
-
description: ".ipa file for the build",
|
456
|
-
optional: true,
|
457
|
-
default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]),
|
458
|
-
FastlaneCore::ConfigItem.new(key: :dsym,
|
459
|
-
env_name: "",
|
460
|
-
description: "zipped .dsym package for the build",
|
461
|
-
optional: true,
|
462
|
-
default_value: Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH]),
|
463
|
-
FastlaneCore::ConfigItem.new(key: :apk,
|
464
|
-
env_name: "",
|
465
|
-
description: ".apk file for the build",
|
466
|
-
optional: true,
|
467
|
-
default_value: Actions.lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]),
|
468
|
-
FastlaneCore::ConfigItem.new(key: :mapping,
|
469
|
-
env_name: "",
|
470
|
-
description: "The path to the mapping.txt file",
|
471
|
-
optional: true,
|
472
|
-
default_value: Actions.lane_context[SharedValues::GRADLE_MAPPING_TXT_OUTPUT_PATH]),
|
473
|
-
FastlaneCore::ConfigItem.new(key: :icon,
|
474
|
-
env_name: "",
|
475
|
-
description: "app icon file to upload",
|
476
|
-
optional: true,
|
477
|
-
default_value: Actions.lane_context[SharedValues::ICON_OUTPUT_PATH]),
|
478
|
-
FastlaneCore::ConfigItem.new(key: :upload_metadata,
|
479
|
-
env_name: "",
|
480
|
-
description: "Upload relevant metadata for this build",
|
481
|
-
optional: true,
|
482
|
-
default_value: true,
|
483
|
-
is_string: false),
|
484
|
-
FastlaneCore::ConfigItem.new(key: :plist_template_path,
|
485
|
-
env_name: "",
|
486
|
-
description: "plist template path",
|
487
|
-
optional: true),
|
488
|
-
FastlaneCore::ConfigItem.new(key: :html_template_path,
|
489
|
-
env_name: "",
|
490
|
-
description: "html erb template path",
|
491
|
-
optional: true),
|
492
|
-
FastlaneCore::ConfigItem.new(key: :html_file_name,
|
493
|
-
env_name: "",
|
494
|
-
description: "uploaded html filename",
|
495
|
-
optional: true),
|
496
|
-
FastlaneCore::ConfigItem.new(key: :version_template_path,
|
497
|
-
env_name: "",
|
498
|
-
description: "version erb template path",
|
499
|
-
optional: true),
|
500
|
-
FastlaneCore::ConfigItem.new(key: :version_file_name,
|
501
|
-
env_name: "",
|
502
|
-
description: "uploaded version filename",
|
503
|
-
optional: true),
|
504
|
-
FastlaneCore::ConfigItem.new(key: :access_key,
|
505
|
-
env_name: "S3_ACCESS_KEY",
|
506
|
-
description: "AWS Access Key ID ",
|
507
|
-
optional: true,
|
508
|
-
default_value: ENV['AWS_ACCESS_KEY_ID']),
|
509
|
-
FastlaneCore::ConfigItem.new(key: :secret_access_key,
|
510
|
-
env_name: "S3_SECRET_ACCESS_KEY",
|
511
|
-
description: "AWS Secret Access Key ",
|
512
|
-
optional: true,
|
513
|
-
default_value: ENV['AWS_SECRET_ACCESS_KEY']),
|
514
|
-
FastlaneCore::ConfigItem.new(key: :bucket,
|
515
|
-
env_name: "S3_BUCKET",
|
516
|
-
description: "AWS bucket name",
|
517
|
-
optional: true,
|
518
|
-
default_value: ENV['AWS_BUCKET_NAME']),
|
519
|
-
FastlaneCore::ConfigItem.new(key: :region,
|
520
|
-
env_name: "S3_REGION",
|
521
|
-
description: "AWS region (for bucket creation) ",
|
522
|
-
optional: true,
|
523
|
-
default_value: ENV['AWS_REGION']),
|
524
|
-
FastlaneCore::ConfigItem.new(key: :acl,
|
525
|
-
env_name: "S3_ACL",
|
526
|
-
description: "Uploaded object permissions e.g public_read (default), private, public_read_write, authenticated_read ",
|
527
|
-
optional: true,
|
528
|
-
default_value: "public-read"),
|
529
|
-
FastlaneCore::ConfigItem.new(key: :release_notes,
|
530
|
-
env_name: "S3_RELEASE_NOTES",
|
531
|
-
description: "Release notes",
|
532
|
-
type: String,
|
533
|
-
optional: true,
|
534
|
-
default_value: Actions.lane_context[SharedValues::RELEASE_NOTES]),
|
535
|
-
FastlaneCore::ConfigItem.new(key: :treat_bucket_as_domain_name,
|
536
|
-
description: "If it's true, it transforms all urls from https://s3.amazonaws.com/BUCKET_NAME to https://BUCKET_NAME",
|
537
|
-
is_string: false,
|
538
|
-
optional: true,
|
539
|
-
default_value: true)
|
540
|
-
]
|
541
|
-
end
|
542
|
-
|
543
|
-
def self.output
|
544
|
-
[
|
545
|
-
['S3_IPA_OUTPUT_PATH', 'Direct HTTP link to the uploaded ipa file'],
|
546
|
-
['S3_DSYM_OUTPUT_PATH', 'Direct HTTP link to the uploaded dsym file'],
|
547
|
-
['S3_PLIST_OUTPUT_PATH', 'Direct HTTP link to the uploaded plist file'],
|
548
|
-
['S3_APK_OUTPUT_PATH', 'Direct HTTP link to the uploaded apk file'],
|
549
|
-
['S3_MAPPING_OUTPUT_PATH', 'Direct HTTP link to the uploaded mapping.txt file'],
|
550
|
-
['S3_HTML_OUTPUT_PATH', 'Direct HTTP link to the uploaded HTML file'],
|
551
|
-
['S3_VERSION_OUTPUT_PATH', 'Direct HTTP link to the uploaded Version file'],
|
552
|
-
['S3_ICON_OUTPUT_PATH', 'Direct HTTP link to the uploaded icon file']
|
553
|
-
]
|
554
|
-
end
|
555
|
-
|
556
|
-
def self.author
|
557
|
-
"joshdholtz"
|
558
|
-
end
|
559
|
-
|
560
|
-
def self.is_supported?(platform)
|
561
|
-
[:ios, :android].include? platform
|
562
|
-
end
|
563
|
-
end
|
564
|
-
end
|
565
|
-
end
|
566
|
-
# rubocop:enable Metrics/AbcSize
|
567
|
-
# rubocop:enable Metrics/MethodLength
|
568
|
-
# rubocop:enable Metrics/ClassLength
|