fastlane-plugin-appcircle_testing_distribution 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/appcircle_testing_distribution/actions/appcircle_testing_distribution_action.rb +39 -31
- data/lib/fastlane/plugin/appcircle_testing_distribution/helper/TDAuthService.rb +34 -5
- data/lib/fastlane/plugin/appcircle_testing_distribution/helper/TDUploadService.rb +16 -15
- data/lib/fastlane/plugin/appcircle_testing_distribution/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04a8808916e178499dd62526d02d5408c1161d6a7faf2b3dab95c5e4f71d83bc
|
|
4
|
+
data.tar.gz: 5cca9f900d1a7a4ac55be0c3672850c11b66b5ec10d6a954f02a8b740b5838b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f56fd4fe450019acf7f09b21782fd27ecef0126512ec9ed12685c768218cfc41ac31f48b6b23eeb63442d1af017610be27d3bcacb637279204082accf6bfada
|
|
7
|
+
data.tar.gz: 5bd6a6082c8f950098c48cc4a741c4969627bda212e1a3f2246f06301c0c7219aa3be370da94a13d3c8517daf6803637e96329c0b6679d4953ac703e99f624a7
|
|
@@ -12,6 +12,7 @@ module Fastlane
|
|
|
12
12
|
class AppcircleTestingDistributionAction < Action
|
|
13
13
|
def self.run(params)
|
|
14
14
|
personalAPIToken = params[:personalAPIToken]
|
|
15
|
+
personalAccessKey = params[:personalAccessKey]
|
|
15
16
|
profileName = params[:profileName]
|
|
16
17
|
appPath = params[:appPath]
|
|
17
18
|
message = params[:message]
|
|
@@ -21,44 +22,47 @@ module Fastlane
|
|
|
21
22
|
|
|
22
23
|
file_extension = File.extname(appPath).downcase
|
|
23
24
|
unless valid_extensions.include?(file_extension)
|
|
24
|
-
|
|
25
|
+
UI.user_error!("Invalid file extension: #{file_extension}. For Android, use .apk or .aab. For iOS, use .ipa or .zip(.xcarchive).")
|
|
25
26
|
end
|
|
26
27
|
|
|
27
|
-
if personalAPIToken.nil?
|
|
28
|
-
|
|
28
|
+
if personalAPIToken.nil? && personalAccessKey.nil?
|
|
29
|
+
UI.user_error!("Either Personal API Token or Personal Access Key is required to authenticate connections to Appcircle services. Please provide a valid access token or access key")
|
|
30
|
+
elsif !personalAPIToken.nil? && !personalAccessKey.nil?
|
|
31
|
+
UI.user_error!("Personal API Token and Personal Access Key cannot be used together. Please provide only one authentication method")
|
|
29
32
|
elsif profileName.nil?
|
|
30
|
-
|
|
33
|
+
UI.user_error!("Distribution profile name is required to distribute applications. Please provide a distribution profile name")
|
|
31
34
|
elsif appPath.nil?
|
|
32
|
-
|
|
35
|
+
UI.user_error!("Application file path is required to distribute applications. Please provide a valid application file path")
|
|
33
36
|
elsif message.nil?
|
|
34
|
-
|
|
37
|
+
UI.user_error!("Message field is required. Please provide a valid message")
|
|
35
38
|
end
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
authToken = self.ac_login(personalAPIToken)
|
|
40
|
+
authToken = self.ac_login(personalAPIToken, personalAccessKey)
|
|
39
41
|
|
|
40
42
|
profileId = TDUploadService.get_profile_id(authToken, profileName, createProfileIfNotExists)
|
|
41
43
|
self.ac_upload(authToken, appPath, profileId, message)
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
def self.ac_login(personalAPIToken)
|
|
45
|
-
|
|
46
|
+
def self.ac_login(personalAPIToken, personalAccessKey)
|
|
47
|
+
if personalAccessKey
|
|
48
|
+
user = TDAuthService.get_ac_token_with_personal_access_key(personal_access_key: personalAccessKey)
|
|
49
|
+
else
|
|
46
50
|
user = TDAuthService.get_ac_token(pat: personalAPIToken)
|
|
47
|
-
UI.success("Login is successful.")
|
|
48
|
-
return user.accessToken
|
|
49
|
-
rescue => e
|
|
50
|
-
puts "Login failed: #{e.message}"
|
|
51
51
|
end
|
|
52
|
+
UI.success("Login is successful.")
|
|
53
|
+
return user.accessToken
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
UI.user_error!("Login failed: #{e.message}")
|
|
52
56
|
end
|
|
53
|
-
|
|
57
|
+
|
|
54
58
|
def self.checkTaskStatus(authToken, taskId)
|
|
55
59
|
uri = URI.parse("https://api.appcircle.io/task/v1/tasks/#{taskId}")
|
|
56
60
|
timeout = 1
|
|
57
|
-
|
|
61
|
+
|
|
58
62
|
response = self.send_request(uri, authToken)
|
|
59
|
-
if response.
|
|
63
|
+
if response.kind_of?(Net::HTTPSuccess)
|
|
60
64
|
stateValue = JSON.parse(response.body)["stateValue"]
|
|
61
|
-
|
|
65
|
+
|
|
62
66
|
if stateValue == 1
|
|
63
67
|
sleep(1)
|
|
64
68
|
return checkTaskStatus(authToken, taskId)
|
|
@@ -83,17 +87,15 @@ module Fastlane
|
|
|
83
87
|
end
|
|
84
88
|
|
|
85
89
|
def self.ac_upload(token, appPath, profileID, message)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
result = self.checkTaskStatus(token, response['taskId'])
|
|
90
|
+
response = TDUploadService.upload_artifact(token: token, message: message, app: appPath, dist_profile_id: profileID)
|
|
91
|
+
result = self.checkTaskStatus(token, response['taskId'])
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
rescue => e
|
|
94
|
-
status_code = e.respond_to?(:response) && e.response ? e.response.code : 'unknown'
|
|
95
|
-
UI.error("Upload failed with status code #{status_code}, with message '#{e.message}'")
|
|
93
|
+
if result
|
|
94
|
+
UI.success("#{appPath} Uploaded to profile id #{profileID} successfully 🎉")
|
|
96
95
|
end
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
status_code = e.respond_to?(:response) && e.response ? e.response.code : 'unknown'
|
|
98
|
+
UI.user_error!("Upload failed with status code #{status_code}, with message '#{e.message}'")
|
|
97
99
|
end
|
|
98
100
|
|
|
99
101
|
def self.description
|
|
@@ -117,16 +119,22 @@ module Fastlane
|
|
|
117
119
|
[
|
|
118
120
|
FastlaneCore::ConfigItem.new(key: :personalAPIToken,
|
|
119
121
|
env_name: "AC_PERSONAL_API_TOKEN",
|
|
120
|
-
description: "Provide Personal API Token to authenticate connections to Appcircle services",
|
|
121
|
-
optional:
|
|
122
|
+
description: "Provide Personal API Token to authenticate connections to Appcircle services (alternative to personalAccessKey)",
|
|
123
|
+
optional: true,
|
|
124
|
+
type: String),
|
|
125
|
+
|
|
126
|
+
FastlaneCore::ConfigItem.new(key: :personalAccessKey,
|
|
127
|
+
env_name: "AC_PERSONAL_ACCESS_KEY",
|
|
128
|
+
description: "Provide Personal Access Key to authenticate connections to Appcircle services (alternative to personalAPIToken)",
|
|
129
|
+
optional: true,
|
|
122
130
|
type: String),
|
|
123
|
-
|
|
131
|
+
|
|
124
132
|
FastlaneCore::ConfigItem.new(key: :profileName,
|
|
125
133
|
env_name: "AC_PROFILE_NAME",
|
|
126
134
|
description: "Enter the profile name of the Appcircle distribution profile. This name uniquely identifies the profile under which your applications will be distributed",
|
|
127
135
|
optional: false,
|
|
128
136
|
type: String),
|
|
129
|
-
|
|
137
|
+
|
|
130
138
|
FastlaneCore::ConfigItem.new(key: :createProfileIfNotExists,
|
|
131
139
|
env_name: "AC_CREATE_PROFILE_IF_NOT_EXISTS",
|
|
132
140
|
description: "If the profile does not exist, create a new profile with the given name",
|
|
@@ -3,7 +3,6 @@ require 'uri'
|
|
|
3
3
|
require 'cgi'
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
class UserResponse
|
|
8
7
|
attr_accessor :accessToken
|
|
9
8
|
|
|
@@ -21,7 +20,7 @@ module TDAuthService
|
|
|
21
20
|
request = Net::HTTP::Post.new(uri)
|
|
22
21
|
request.content_type = 'application/x-www-form-urlencoded'
|
|
23
22
|
request['Accept'] = 'application/json'
|
|
24
|
-
|
|
23
|
+
|
|
25
24
|
# Encode parameters
|
|
26
25
|
params = { pat: pat }
|
|
27
26
|
request.body = URI.encode_www_form(params)
|
|
@@ -31,10 +30,40 @@ module TDAuthService
|
|
|
31
30
|
http.request(request)
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
# Check response
|
|
34
|
+
if response.kind_of?(Net::HTTPSuccess)
|
|
35
|
+
response_data = JSON.parse(response.body)
|
|
36
|
+
|
|
37
|
+
user = UserResponse.new(
|
|
38
|
+
accessToken: response_data['access_token']
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return user
|
|
42
|
+
else
|
|
43
|
+
raise "HTTP Request failed (#{response.code} #{response.message})"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.get_ac_token_with_personal_access_key(personal_access_key:)
|
|
48
|
+
endpoint_url = 'https://auth.appcircle.io/auth/v1/token'
|
|
49
|
+
uri = URI(endpoint_url)
|
|
50
|
+
|
|
51
|
+
# Create HTTP request
|
|
52
|
+
request = Net::HTTP::Post.new(uri)
|
|
53
|
+
request.content_type = 'application/x-www-form-urlencoded'
|
|
54
|
+
request['Accept'] = 'application/json'
|
|
55
|
+
|
|
56
|
+
# Encode parameters
|
|
57
|
+
params = { 'personal-access-key' => personal_access_key }
|
|
58
|
+
request.body = URI.encode_www_form(params)
|
|
59
|
+
|
|
60
|
+
# Make the HTTP request
|
|
61
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
|
62
|
+
http.request(request)
|
|
63
|
+
end
|
|
35
64
|
|
|
36
65
|
# Check response
|
|
37
|
-
if response.
|
|
66
|
+
if response.kind_of?(Net::HTTPSuccess)
|
|
38
67
|
response_data = JSON.parse(response.body)
|
|
39
68
|
|
|
40
69
|
user = UserResponse.new(
|
|
@@ -46,4 +75,4 @@ module TDAuthService
|
|
|
46
75
|
raise "HTTP Request failed (#{response.code} #{response.message})"
|
|
47
76
|
end
|
|
48
77
|
end
|
|
49
|
-
end
|
|
78
|
+
end
|
|
@@ -10,17 +10,20 @@ module TDUploadService
|
|
|
10
10
|
url = "https://api.appcircle.io/distribution/v2/profiles/#{dist_profile_id}/app-versions"
|
|
11
11
|
headers = {
|
|
12
12
|
Authorization: "Bearer #{token}",
|
|
13
|
-
|
|
14
|
-
content_type: :multipart
|
|
13
|
+
content_type: :multipart # multipart/form-data
|
|
15
14
|
}
|
|
16
15
|
payload = {
|
|
17
16
|
Message: message,
|
|
18
17
|
File: File.new(app, 'rb')
|
|
19
18
|
}
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
begin
|
|
22
21
|
response = RestClient.post(url, payload, headers)
|
|
23
|
-
|
|
22
|
+
begin
|
|
23
|
+
JSON.parse(response.body)
|
|
24
|
+
rescue StandardError
|
|
25
|
+
response.body
|
|
26
|
+
end
|
|
24
27
|
rescue RestClient::ExceptionWithResponse => e
|
|
25
28
|
raise e
|
|
26
29
|
rescue StandardError => e
|
|
@@ -30,18 +33,16 @@ module TDUploadService
|
|
|
30
33
|
|
|
31
34
|
def self.get_distribution_profiles(auth_token:)
|
|
32
35
|
url = "#{BASE_URL}/distribution/v2/profiles"
|
|
33
|
-
|
|
36
|
+
|
|
34
37
|
# Set up the headers with authentication
|
|
35
38
|
headers = {
|
|
36
39
|
Authorization: "Bearer #{auth_token}",
|
|
37
40
|
accept: 'application/json'
|
|
38
41
|
}
|
|
39
|
-
|
|
42
|
+
|
|
40
43
|
begin
|
|
41
44
|
response = RestClient.get(url, headers)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
parsed_response
|
|
45
|
+
JSON.parse(response.body)
|
|
45
46
|
rescue RestClient::ExceptionWithResponse => e
|
|
46
47
|
raise e
|
|
47
48
|
rescue StandardError => e
|
|
@@ -59,7 +60,7 @@ module TDUploadService
|
|
|
59
60
|
payload = {
|
|
60
61
|
name: name
|
|
61
62
|
}.to_json
|
|
62
|
-
|
|
63
|
+
|
|
63
64
|
begin
|
|
64
65
|
response = RestClient.post(url, payload, headers)
|
|
65
66
|
JSON.parse(response.body)
|
|
@@ -80,28 +81,28 @@ module TDUploadService
|
|
|
80
81
|
profileId = profile['id']
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
|
-
rescue => e
|
|
84
|
+
rescue StandardError => e
|
|
84
85
|
raise "Something went wrong while fetching profiles: #{e.message}"
|
|
85
86
|
end
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
if profileId.nil? && !createProfileIfNotExists
|
|
88
89
|
raise "Error: The test profile '#{profileName}' could not be found. The option 'createProfileIfNotExists' is set to false, so no new profile was created. To automatically create a new profile if it doesn't exist, set 'createProfileIfNotExists' to true."
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
if profileId.nil? && createProfileIfNotExists
|
|
92
93
|
begin
|
|
93
|
-
puts
|
|
94
|
+
puts("The test profile '#{profileName}' could not be found. A new profile is being created...")
|
|
94
95
|
new_profile = TDUploadService.create_distribution_profile(name: profileName, auth_token: authToken)
|
|
95
96
|
if new_profile.nil?
|
|
96
97
|
raise "Error: The new profile could not be created."
|
|
97
98
|
end
|
|
99
|
+
|
|
98
100
|
profileId = new_profile['id']
|
|
99
|
-
rescue => e
|
|
101
|
+
rescue StandardError => e
|
|
100
102
|
raise "Something went wrong while creating a new profile: #{e.message}"
|
|
101
103
|
end
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
return profileId
|
|
105
107
|
end
|
|
106
|
-
|
|
107
108
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane-plugin-appcircle_testing_distribution
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- appcircleio
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-11-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rest-client
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
19
|
+
version: '2.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: '0'
|
|
26
|
+
version: '2.0'
|
|
27
27
|
description:
|
|
28
28
|
email: cloud@appcircle.io
|
|
29
29
|
executables: []
|
|
@@ -45,7 +45,7 @@ homepage: https://github.com/appcircleio/fastlane_plugin_appcircle_testing_distr
|
|
|
45
45
|
licenses:
|
|
46
46
|
- MIT
|
|
47
47
|
metadata:
|
|
48
|
-
rubygems_mfa_required: '
|
|
48
|
+
rubygems_mfa_required: 'true'
|
|
49
49
|
post_install_message:
|
|
50
50
|
rdoc_options: []
|
|
51
51
|
require_paths:
|
|
@@ -61,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
62
|
version: '0'
|
|
63
63
|
requirements: []
|
|
64
|
-
rubygems_version: 3.4.
|
|
64
|
+
rubygems_version: 3.4.10
|
|
65
65
|
signing_key:
|
|
66
66
|
specification_version: 4
|
|
67
67
|
summary: Efficiently distribute application builds to users or testing groups using
|