Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
FuryLion Fastlane plugin
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Packages
Packages
Container Registry
Analytics
CI / CD Analytics
Repository Analytics
Value Stream Analytics
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vadim Vlasov
FuryLion Fastlane plugin
Commits
aeebc047
Commit
aeebc047
authored
Sep 26, 2024
by
Vadim Vlasov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Chunked Upload implemented
parent
cfcf8c75
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
229 additions
and
28 deletions
+229
-28
lib/fastlane/plugin/furylion/actions/appgate_upload.rb
lib/fastlane/plugin/furylion/actions/appgate_upload.rb
+33
-27
lib/fastlane/plugin/furylion/helper/appgate_helper.rb
lib/fastlane/plugin/furylion/helper/appgate_helper.rb
+195
-0
lib/fastlane/plugin/furylion/version.rb
lib/fastlane/plugin/furylion/version.rb
+1
-1
No files found.
lib/fastlane/plugin/furylion/actions/appgate_upload.rb
View file @
aeebc047
...
@@ -2,42 +2,42 @@ module Fastlane
...
@@ -2,42 +2,42 @@ module Fastlane
module
Actions
module
Actions
class
AppgateUploadAction
<
Action
class
AppgateUploadAction
<
Action
def
self
.
run
(
params
)
def
self
.
run
(
params
)
require
'faraday'
require
'faraday_middleware'
Helper
::
AppGateHelper
.
verify_required_params
(
params
)
api_key
=
params
[
:api_key
]
app_id
=
params
[
:app_id
]
app_id
=
params
[
:app_id
]
file_path
=
params
[
:file_path
]
file_path
=
params
[
:file_path
]
branch
=
params
[
:branch
]
branch
=
params
[
:branch
]
api_key
=
"bearer "
+
params
[
:api_key
]
include_branch
=
params
[
:include_branch
]
include_branch
=
params
[
:include_branch
]
skip_waiting_for_release
=
params
[
:skip_waiting_for_release
]
url
=
"https://apps.furylion.net/api/app/
#{
app_id
}
/upload"
if
!
include_branch
branch
=
""
UI
.
message
(
"Uploading binary..."
)
conn
=
Faraday
.
new
(
url:
url
)
do
|
faraday
|
faraday
.
request
:multipart
faraday
.
request
:url_encoded
faraday
.
adapter
Faraday
.
default_adapter
faraday
.
options
.
timeout
=
600
faraday
.
options
.
open_timeout
=
10
end
end
payload
=
{
UI
.
message
(
"Starting release upload..."
)
file:
Faraday
::
UploadIO
.
new
(
file_path
,
'application/octet-stream'
)
release_data
=
Helper
::
AppGateHelper
.
create_release
(
api_key
,
app_id
,
branch
,
File
.
basename
(
file_path
),
File
.
size
(
file_path
))
}
UI
.
abort_with_message!
(
"Failed to create release"
)
unless
release_data
payload
[
:branch
]
=
branch
if
include_branch
response
=
conn
.
post
do
|
req
|
release_id
=
release_data
[
:release_id
]
req
.
headers
[
'Authorization'
]
=
api_key
upload_token
=
release_data
[
:upload_token
]
req
.
body
=
payload
end
case
response
.
status
uploaded
=
Helper
::
AppGateHelper
.
upload_file_parallel
(
release_id
,
file_path
,
upload_token
)
when
200
..
205
UI
.
abort_with_message!
(
"Failed to upload file"
)
unless
uploaded
UI
.
success
(
"Upload complete!"
)
when
401
UI
.
message
(
"Finishing release..."
)
UI
.
user_error!
(
"Auth Error, provided invalid token"
)
finished
=
Helper
::
AppGateHelper
.
finish_upload
(
release_id
,
upload_token
)
when
400
...
407
,
409
...
428
,
430
...
499
UI
.
abort_with_message!
(
"Failed to finish upload"
)
unless
finished
UI
.
user_error!
(
"Client error:
#{
response
.
status
}
:
#{
response
.
body
}
"
)
if
skip_waiting_for_release
UI
.
success
(
"Successfully uploaded release! Skipping wait for processing."
)
else
else
UI
.
user_error!
(
"Unexpected error:
#{
response
.
status
}
:
#{
response
.
body
}
"
)
UI
.
message
(
"Waiting for release to be ready..."
)
release_ready
=
Helper
::
AppGateHelper
.
wait_for_release_to_be_ready
(
release_id
,
upload_token
)
UI
.
abort_with_message!
(
"Failed to wait for release to be ready"
)
unless
release_ready
UI
.
success
(
"Successfully uploaded and finished release!"
)
end
end
end
end
...
@@ -76,7 +76,13 @@ module Fastlane
...
@@ -76,7 +76,13 @@ module Fastlane
FastlaneCore
::
ConfigItem
.
new
(
key: :api_key
,
FastlaneCore
::
ConfigItem
.
new
(
key: :api_key
,
env_name:
"APPGATE_API_KEY"
,
env_name:
"APPGATE_API_KEY"
,
description:
"API key for AppGate"
,
description:
"API key for AppGate"
,
sensitive:
true
)
sensitive:
true
),
FastlaneCore
::
ConfigItem
.
new
(
key: :skip_waiting_for_release
,
env_name:
"APPGATE_SKIP_WAITING_FOR_RELEASE"
,
description:
"Skip waiting for release processing"
,
optional:
true
,
is_string:
false
,
default_value:
false
)
]
]
end
end
...
...
lib/fastlane/plugin/furylion/helper/appgate_helper.rb
0 → 100644
View file @
aeebc047
module
Fastlane
module
Helper
class
AppGateHelper
BASE_URL
=
"https://apps.furylion.net/api"
CHUNK_SIZE
=
4
*
1024
*
1024
# 4MB
# Maximum number of retries for a request
MAX_RETRIES
=
5
# Delay between retries in seconds
RETRY_DELAY
=
5
# Time to wait between 2 status polls in seconds
RELEASE_UPLOAD_STATUS_POLL_INTERVAL
=
1
def
self
.
verify_required_params
(
params
)
required_params
=
[
:api_key
,
:app_id
,
:file_path
]
required_params
.
each
do
|
param
|
UI
.
user_error!
(
"Missing required parameter:
#{
param
}
"
)
unless
params
[
param
]
end
end
def
self
.
create_release
(
api_key
,
app_id
,
branch
,
file_name
,
file_size
)
url
=
"
#{
BASE_URL
}
/app/
#{
app_id
}
/releases"
body
=
{
branch:
branch
,
size:
file_size
,
file_name:
file_name
}
response
=
self
.
request_with_retry
(
:post
,
url
,
api_key
,
body
)
return
{
release_id:
response
[
'release_id'
],
upload_token:
response
[
'upload_token'
]
}
if
response
&&
response
[
'release_id'
]
&&
response
[
'upload_token'
]
nil
end
def
self
.
upload_file
(
release_id
,
file
,
upload_token
)
File
.
open
(
file
,
'rb'
)
do
|
f
|
chunk_number
=
0
until
f
.
eof?
chunk
=
f
.
read
(
CHUNK_SIZE
)
unless
upload_chunk
(
release_id
,
upload_token
,
chunk
,
chunk_number
)
return
false
end
chunk_number
+=
1
UI
.
message
(
"Uploaded chunk
#{
chunk_number
}
"
)
end
UI
.
message
(
"Binary uploaded"
)
end
true
end
def
self
.
human_readable_size
(
size_in_bytes
)
units
=
[
'B'
,
'KB'
,
'MB'
,
'GB'
,
'TB'
]
index
=
0
size
=
size_in_bytes
.
to_f
while
size
>=
1024
&&
index
<
units
.
length
-
1
size
/=
1024
index
+=
1
end
return
sprintf
(
"%.2f %s"
,
size
,
units
[
index
])
end
def
self
.
upload_file_parallel
(
release_id
,
file
,
upload_token
,
max_threads
=
5
)
file_size
=
File
.
size
(
file
)
chunk_count
=
(
file_size
.
to_f
/
CHUNK_SIZE
).
ceil
UI
.
message
(
"Uploading release binary..."
)
UI
.
message
(
"File size:
#{
human_readable_size
(
file_size
)
}
"
)
UI
.
message
(
"Number of chunks:
#{
chunk_count
}
"
)
UI
.
message
(
"Using
#{
max_threads
}
threads for parallel upload"
)
queue
=
Queue
.
new
chunk_count
.
times
{
|
i
|
queue
<<
i
}
mutex
=
Mutex
.
new
# Добавляем мьютекс для синхронизации вывода
threads
=
max_threads
.
times
.
map
do
Thread
.
new
do
while
(
chunk_number
=
queue
.
pop
(
true
)
rescue
nil
)
File
.
open
(
file
,
'rb'
)
do
|
f
|
f
.
seek
(
chunk_number
*
CHUNK_SIZE
)
chunk
=
f
.
read
(
CHUNK_SIZE
)
if
upload_chunk
(
release_id
,
upload_token
,
chunk
,
chunk_number
)
mutex
.
synchronize
{
UI
.
message
(
"Uploaded chunk
#{
chunk_number
}
"
)
}
else
mutex
.
synchronize
{
UI
.
error
(
"Failed to upload chunk
#{
chunk_number
}
"
)
}
end
end
end
end
end
threads
.
each
(
&
:join
)
UI
.
message
(
"Binary uploaded"
)
true
end
def
self
.
upload_chunk
(
release_id
,
upload_token
,
chunk
,
chunk_number
)
url
=
"
#{
BASE_URL
}
/release/
#{
release_id
}
/upload/chunk"
query
=
{
token:
upload_token
,
block_number:
chunk_number
}
response
=
self
.
request_with_retry
(
:post
,
url
,
nil
,
chunk
,
query
)
response
.
success?
end
def
self
.
finish_upload
(
release_id
,
upload_token
)
url
=
"
#{
BASE_URL
}
/release/
#{
release_id
}
/upload/finish"
query
=
{
token:
upload_token
}
response
=
self
.
request_with_retry
(
:post
,
url
,
nil
,
nil
,
query
)
response
.
success?
end
def
self
.
request_with_retry
(
method
,
url
,
api_key
=
nil
,
body
=
nil
,
query
=
nil
)
retries
=
0
begin
response
=
self
.
request
(
method
,
url
,
api_key
,
body
,
query
)
if
response
.
nil?
raise
"Request failed with nil response"
end
return
response
rescue
=>
e
UI
.
error
(
"Error occurred:
#{
e
.
message
}
"
)
if
retries
<
MAX_RETRIES
retries
+=
1
UI
.
message
(
"Retrying in
#{
RETRY_DELAY
}
seconds (attempt
#{
retries
}
/
#{
MAX_RETRIES
}
)..."
)
sleep
(
RETRY_DELAY
)
retry
else
UI
.
user_error!
(
"Max retries reached. Request failed."
)
end
end
end
def
self
.
request
(
method
,
url
,
api_key
=
nil
,
body
=
nil
,
query
=
nil
)
headers
=
{}
headers
[
'Authorization'
]
=
"Bearer
#{
api_key
}
"
if
api_key
headers
[
'Content-Type'
]
=
'application/json'
unless
headers
[
'Content-Type'
]
begin
response
=
Faraday
.
new
.
send
(
method
)
do
|
req
|
req
.
url
url
req
.
headers
=
headers
req
.
params
=
query
if
query
if
body
if
headers
[
'Content-Type'
]
==
'application/json'
&&
body
.
is_a?
(
Hash
)
req
.
body
=
body
.
to_json
else
req
.
body
=
body
end
end
end
if
response
.
success?
return
JSON
.
parse
(
response
.
body
)
if
response
.
body
&&
!
response
.
body
.
empty?
&&
headers
[
'Content-Type'
]
==
'application/json'
return
response
else
UI
.
error
(
"Error:
#{
response
.
status
}
-
#{
response
.
body
}
"
)
return
nil
end
rescue
Faraday
::
Error
=>
e
UI
.
error
(
"Network error:
#{
e
}
"
)
return
nil
end
end
def
self
.
wait_for_release_to_be_ready
(
release_id
,
upload_token
)
url
=
"
#{
BASE_URL
}
/release/
#{
release_id
}
/status"
query
=
{
token:
upload_token
,
}
loop
do
response
=
self
.
request_with_retry
(
:get
,
url
,
nil
,
nil
,
query
)
if
response
&&
response
[
'status'
]
case
response
[
'status'
]
when
'UploadFinished'
return
true
when
'UploadFailed'
UI
.
user_error!
(
"Upload failed:
#{
response
[
'error_message'
]
}
"
)
return
false
end
else
UI
.
error
(
"Failed to get release status"
)
end
sleep
(
RELEASE_UPLOAD_STATUS_POLL_INTERVAL
)
end
end
end
end
end
\ No newline at end of file
lib/fastlane/plugin/furylion/version.rb
View file @
aeebc047
module
Fastlane
module
Fastlane
module
Furylion
module
Furylion
VERSION
=
"1.
2.1
"
VERSION
=
"1.
3.0
"
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment