fastlane-plugin-appcircle_enterprise_app_store 0.0.1
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/LICENSE +21 -0
- data/README.md +105 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store/actions/appcircle_enterprise_app_store_action.rb +192 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store/helper/appcircle_enterprise_app_store_helper.rb +16 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store/helper/auth_service.rb +49 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store/helper/upload_service.rb +110 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store/version.rb +5 -0
- data/lib/fastlane/plugin/appcircle_enterprise_app_store.rb +16 -0
- metadata +65 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6d8856c9fc564231df28f4de8dfa86c654b63e39953c16985425944abf4a41f6
|
|
4
|
+
data.tar.gz: 9ac3b5154d041cc5c973de767f8fb22812e85078e37bcb1d8f649aad7bee4d38
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cb5cf60eb158cb46a539f6cf55032b8b8f952dfe1011ffa95773b53fa5bdbda668515adf00a0edbfea1b64f9200089218b8d20b4498a3af67f5160fcf6c62ed2
|
|
7
|
+
data.tar.gz: a1c96695801bb0eb112926c3201799881731d4fa51c4aaff5d908d767d1532ecc4355f143859674766faabe3d3660bf749c74abced9e0726d12cb82532feec15
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Guven Karanfil <guven.karanfil@smartface.io>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
## Appcircle Enterprise App Store
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/fastlane-plugin-appcircle_enterprise_store)
|
|
4
|
+
|
|
5
|
+
Appcircle Enterprise Mobile App Store is your own mobile app store for providing access to in-house apps with a customizable mobile storefront.
|
|
6
|
+
|
|
7
|
+
- **Customizable Storefront:** Distribute your in-house apps with a fully customizable mobile storefront.
|
|
8
|
+
- **Secure Distribution:** Everything you need for secure, streamlined distribution of your in-house apps.
|
|
9
|
+
- **No MDM Required:** Allows distribution of B2B and B2E applications without the need for an MDM solution and enrollment.
|
|
10
|
+
|
|
11
|
+
Learn more about [Appcircle Enterprise App Store](https://appcircle.io/enterprise-app-store?utm_source=fastlane&utm_medium=plugin&utm_campaign=enterprise_app_store).
|
|
12
|
+
|
|
13
|
+
## What Sets Apart Appcircle Enterprise Mobile App Store
|
|
14
|
+
|
|
15
|
+
1. **Direct File Sharing:**
|
|
16
|
+
- **Skip Traditional Stores:** Share .IPA, APK, or AAB files directly, avoiding the need to wait for Apple App Store or Google Play approvals.
|
|
17
|
+
2. **Flexible Sharing Options:**
|
|
18
|
+
- **Beta and Live Modes:** Share your app in ‘beta’ mode for testing new features or identifying bugs, or in ‘live’ mode for stable versions. This flexibility helps maintain the development lifecycle without interruptions.
|
|
19
|
+
3. **Enhanced Security:**
|
|
20
|
+
- **Secure Authentication:** Access the Enterprise Mobile App Store with extra secure authentication using Enterprise Authentication Methods.
|
|
21
|
+
- **Controlled Access:** Ensure that only authorized users can access the app store and its contents.
|
|
22
|
+
4. **Customizable Mobile Storefront:**
|
|
23
|
+
- **Tailored Experience:** Provide a customizable mobile storefront for your in-house apps, ensuring a tailored experience that aligns with your brand and user needs.
|
|
24
|
+
5. **No MDM Requirement:**
|
|
25
|
+
- **Simplified Distribution:** Distribute B2B and B2E applications without the need for a Mobile Device Management (MDM) solution or enrollment, reducing complexity and costs.
|
|
26
|
+
6. **Streamlined Workflow:**
|
|
27
|
+
- **Seamless Integration:** Integrates smoothly with your existing workflow, making it easy to manage and distribute apps within your organization.
|
|
28
|
+
- **Efficient Management:** Track and manage applications, versions, testers, and teams effectively, ensuring a smooth distribution process.
|
|
29
|
+
|
|
30
|
+
These features make the Appcircle Enterprise Mobile App Store a powerful tool for securely and efficiently distributing in-house applications, offering flexibility, enhanced security, and a streamlined workflow.
|
|
31
|
+
|
|
32
|
+
## System Requirements
|
|
33
|
+
|
|
34
|
+
**Compatible Agents:**
|
|
35
|
+
|
|
36
|
+
- macOS 14.2, 14.5
|
|
37
|
+
|
|
38
|
+
**Supported Version:**
|
|
39
|
+
|
|
40
|
+
- Fastlane 2.222.0
|
|
41
|
+
- Ruby 3.2.2
|
|
42
|
+
|
|
43
|
+
Note: We currently support **Appcircle Cloud**, with **self-hosted** support planned in our roadmap.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
### Generating/Managing the Personal API Tokens
|
|
48
|
+
|
|
49
|
+
To generate a Personal API Token:
|
|
50
|
+
|
|
51
|
+
1. Go to the My Organization screen (second option at the bottom left).
|
|
52
|
+
2. Find the Personal API Token section in the top right corner.
|
|
53
|
+
3. Press the "Generate Token" button to generate your first token.
|
|
54
|
+
|
|
55
|
+
.png>)
|
|
56
|
+
|
|
57
|
+
### Getting Started
|
|
58
|
+
|
|
59
|
+
This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `appcircle_enterprise_app_store`, add it to your project by running:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
fastlane add_plugin appcircle_enterprise_app_store
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
After adding the plugin to your project, configure your Fastfile as follows:
|
|
66
|
+
|
|
67
|
+
```yml
|
|
68
|
+
lane :distribute_app_store do
|
|
69
|
+
appcircle_enterprise_app_store(
|
|
70
|
+
personalAPIToken: "$(AC_PERSONAL_API_TOKEN)",
|
|
71
|
+
appPath: "$(APP_PATH)",
|
|
72
|
+
summary: "$(SUMMARY)",
|
|
73
|
+
releaseNotes: "$(RELEASE_NOTE)",
|
|
74
|
+
publishType: "$(PUBLISH_TYPE)" # Assign the appropriate number based on the status: None (0), Beta (1), Live (2)
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `personalAPIToken`: The Appcircle Personal API token is utilized to authenticate and secure access to Appcircle services, ensuring that only authorized users can perform actions within the platform.
|
|
80
|
+
- `appPath`: Indicates the file path to the application that will be uploaded to Appcircle Testing Distribution Profile.
|
|
81
|
+
- `releaseNote`: Contains the details of changes, updates, and improvements made in the current version of the app being published.
|
|
82
|
+
- `Summary`: Used to provide a brief overview of the version of the app that is about to be published.
|
|
83
|
+
- `publishType`: Specifies the publishing status as either none, beta, or live, and must be assigned the values "0", "1", or "2" accordingly.
|
|
84
|
+
|
|
85
|
+
**Ensure that this action is added after build steps have been completed.**
|
|
86
|
+
|
|
87
|
+
**If two workflows start simultaneously, the last workflow to reach the publish step will be the up-to-date version on the Enterprise App Store. If these workflows building the same package version, the first publish will be successful, while later deployments with the same version will fail.**
|
|
88
|
+
|
|
89
|
+
### Leveraging Environment Variables
|
|
90
|
+
|
|
91
|
+
Utilize environment variables seamlessly by substituting the parameters with $(VARIABLE_NAME) in your task inputs. The extension automatically retrieves values from the specified environment variables within your pipeline.
|
|
92
|
+
|
|
93
|
+
If you would like to learn more about this extension and how to utilize it in your projects, please [contact us](https://appcircle.io/contact?utm_source=fastlane&utm_medium=plugin&utm_campaign=enterprise_app_store)
|
|
94
|
+
|
|
95
|
+
## Issues and Feedback
|
|
96
|
+
|
|
97
|
+
For any other issues and feedback about this plugin, please submit it to this repository.
|
|
98
|
+
|
|
99
|
+
## Troubleshooting
|
|
100
|
+
|
|
101
|
+
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
|
102
|
+
|
|
103
|
+
### Reference
|
|
104
|
+
|
|
105
|
+
For more detailed instructions and support, visit the [Appcircle Enterprise App Store documentation](https://appcircle.io/enterprise-app-store).
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
require 'fastlane/action'
|
|
7
|
+
require_relative '../helper/appcircle_enterprise_app_store_helper'
|
|
8
|
+
|
|
9
|
+
require_relative '../helper/auth_service'
|
|
10
|
+
require_relative '../helper/upload_service'
|
|
11
|
+
|
|
12
|
+
module Fastlane
|
|
13
|
+
module Actions
|
|
14
|
+
class AppcircleEnterpriseAppStoreAction < Action
|
|
15
|
+
@@apiToken = nil
|
|
16
|
+
|
|
17
|
+
def self.run(params)
|
|
18
|
+
personalAPIToken = params[:personalAPIToken]
|
|
19
|
+
appPath = params[:appPath]
|
|
20
|
+
summary = params[:summary]
|
|
21
|
+
releaseNotes = params[:releaseNotes]
|
|
22
|
+
publishType = params[:publishType]
|
|
23
|
+
|
|
24
|
+
valid_extensions = ['.apk', '.ipa']
|
|
25
|
+
|
|
26
|
+
file_extension = File.extname(appPath).downcase
|
|
27
|
+
unless valid_extensions.include?(file_extension)
|
|
28
|
+
raise "Invalid file extension: #{file_extension}. For Android, use .apk. For iOS, use .ipa."
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if personalAPIToken.nil?
|
|
32
|
+
raise UI.error("Please provide Personal API Token to authenticate connections to Appcircle services")
|
|
33
|
+
elsif appPath.nil?
|
|
34
|
+
raise UI.error("Please specify the path to your application file. For iOS, this can be a .ipa or .xcarchive file path. For Android, specify the .apk or .appbundle file path")
|
|
35
|
+
elsif summary.nil?
|
|
36
|
+
raise UI.error("Please provide a summary for the application to be published. This summary will be displayed in the Appcircle Enterprise App Store")
|
|
37
|
+
elsif releaseNotes.nil?
|
|
38
|
+
raise UI.error("Please provide release notes for the application to be published. These notes will be displayed in the Appcircle Enterprise App Store")
|
|
39
|
+
elsif publishType.nil?
|
|
40
|
+
raise UI.error("Please specify the publish type for the application. This can be 0: None, 1: Beta, 2: Live. Default is 0: None. For more information, provide the number of the publish type")
|
|
41
|
+
elsif publishType != "0" && publishType != "1" && publishType != "2"
|
|
42
|
+
raise UI.error("Please provide a valid publish type. This can be 0: None, 1: Beta, 2: Live. Default is 0: None. For more information, provide the number of the publish type")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
self.ac_login(personalAPIToken)
|
|
47
|
+
self.uploadToProfile(appPath, summary, releaseNotes, publishType)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def self.ac_login(accessToken)
|
|
52
|
+
begin
|
|
53
|
+
user = AuthService.get_ac_token(pat: accessToken)
|
|
54
|
+
UI.success("Login is successful.")
|
|
55
|
+
@@apiToken = user.accessToken
|
|
56
|
+
rescue => e
|
|
57
|
+
UI.error("Login failed: #{e.message}")
|
|
58
|
+
raise e
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def self.checkTaskStatus(taskId)
|
|
64
|
+
uri = URI.parse("https://api.appcircle.io/task/v1/tasks/#{taskId}")
|
|
65
|
+
timeout = 1
|
|
66
|
+
|
|
67
|
+
response = self.send_request(uri, @@apiToken)
|
|
68
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
69
|
+
stateValue = JSON.parse(response.body)["stateValue"]
|
|
70
|
+
if stateValue == 1
|
|
71
|
+
sleep(1)
|
|
72
|
+
return checkTaskStatus(taskId)
|
|
73
|
+
end
|
|
74
|
+
if stateValue == 3
|
|
75
|
+
return true
|
|
76
|
+
else
|
|
77
|
+
taskStatus = {
|
|
78
|
+
0 => "Unknown",
|
|
79
|
+
1 => "Begin",
|
|
80
|
+
2 => "Canceled",
|
|
81
|
+
3 => 'Completed',
|
|
82
|
+
}
|
|
83
|
+
raise UI.error("#{taskId} id upload request failed with status #{taskStatus[stateValue]}.")
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
"Upload failed with response code #{response.code} and message '#{response.message}'"
|
|
87
|
+
raise
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def self.uploadToProfile(appPath, summary, releaseNotes, publishType)
|
|
93
|
+
response = UploadService.upload_artifact(token: @@apiToken, app: appPath)
|
|
94
|
+
result = self.checkTaskStatus(response["taskId"])
|
|
95
|
+
|
|
96
|
+
if result
|
|
97
|
+
profileId = UploadService.getProfileId(authToken: @@apiToken)
|
|
98
|
+
appVersions = UploadService.getAppVersions(auth_token: @@apiToken, entProfileId: profileId)
|
|
99
|
+
appVersionId = UploadService.getVersionId(versionList: appVersions)
|
|
100
|
+
if publishType != "0"
|
|
101
|
+
self.publishToStore(profileId, appVersionId, summary, releaseNotes, publishType)
|
|
102
|
+
end
|
|
103
|
+
UI.success("#{appPath} uploaded to the Appcircle Enterprise Store successfully")
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.publishToStore(entProfileId, entVersionId, summary, releaseNote, publishType)
|
|
108
|
+
begin
|
|
109
|
+
options = {
|
|
110
|
+
auth_token: @@apiToken,
|
|
111
|
+
ent_profile_id: entProfileId,
|
|
112
|
+
ent_version_id: entVersionId,
|
|
113
|
+
summary: summary,
|
|
114
|
+
release_notes: releaseNote,
|
|
115
|
+
publish_type: publishType
|
|
116
|
+
}
|
|
117
|
+
response = UploadService.publishVersion(options)
|
|
118
|
+
rescue => e
|
|
119
|
+
UI.error("App could not publish at Enterprise App Store. #{e&.response}")
|
|
120
|
+
raise e
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.send_request(uri, access_token)
|
|
125
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
126
|
+
http.use_ssl = (uri.scheme == "https")
|
|
127
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
|
128
|
+
request["Authorization"] = "Bearer #{access_token}"
|
|
129
|
+
http.request(request)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def self.description
|
|
133
|
+
"Efficiently publish your apps to Appcircle Enterprise Store"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def self.authors
|
|
137
|
+
["Guven Karanfil"]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.return_value
|
|
141
|
+
# If your method provides a return value, you can describe here what it does
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.details
|
|
145
|
+
# Optional:
|
|
146
|
+
"Appcircle Enterprise Mobile App Store is your own mobile app store for providing access to in-house apps with a customizable mobile storefront"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def self.available_options
|
|
150
|
+
[
|
|
151
|
+
FastlaneCore::ConfigItem.new(key: :personalAPIToken,
|
|
152
|
+
env_name: "AC_PERSONAL_API_TOKEN",
|
|
153
|
+
description: "Provide Personal API Token to authenticate Appcircle services",
|
|
154
|
+
optional: false,
|
|
155
|
+
type: String),
|
|
156
|
+
|
|
157
|
+
FastlaneCore::ConfigItem.new(key: :appPath,
|
|
158
|
+
env_name: "AC_APP_PATH",
|
|
159
|
+
description: "Specify the path to your application file. For iOS, this can be a .ipa or .xcarchive file path. For Android, specify the .apk or .appbundle file path",
|
|
160
|
+
optional: false,
|
|
161
|
+
type: String),
|
|
162
|
+
|
|
163
|
+
FastlaneCore::ConfigItem.new(key: :summary,
|
|
164
|
+
env_name: "AC_SUMMARY",
|
|
165
|
+
description: "Provide a summary for the application to be published. This summary will be displayed in the Appcircle Enterprise App Store",
|
|
166
|
+
optional: false,
|
|
167
|
+
type: String),
|
|
168
|
+
|
|
169
|
+
FastlaneCore::ConfigItem.new(key: :releaseNotes,
|
|
170
|
+
env_name: "AC_RELEASE_NOTES",
|
|
171
|
+
description: "Provide release notes for the application to be published. These notes will be displayed in the Appcircle Enterprise App Store",
|
|
172
|
+
optional: false,
|
|
173
|
+
type: String),
|
|
174
|
+
|
|
175
|
+
FastlaneCore::ConfigItem.new(key: :publishType,
|
|
176
|
+
env_name: "AC_PUBLISH_TYPE",
|
|
177
|
+
description: "Specify the publish type for the application. This can be 0: None, 1: Beta, 2: Live. Default is 0: None. For more information, provide the number of the publish type",
|
|
178
|
+
optional: false,
|
|
179
|
+
type: String),
|
|
180
|
+
]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def self.is_supported?(platform)
|
|
184
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
|
185
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
|
186
|
+
#
|
|
187
|
+
# [:ios, :mac, :android].include?(platform)
|
|
188
|
+
true
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
|
|
5
|
+
|
|
6
|
+
module Helper
|
|
7
|
+
class AppcircleEnterpriseAppStoreHelper
|
|
8
|
+
# class methods that you define here become available in your action
|
|
9
|
+
# as `Helper::AppcircleEnterpriseAppStoreHelper.your_method`
|
|
10
|
+
#
|
|
11
|
+
def self.show_message
|
|
12
|
+
UI.message("Hello from the appcircle_enterprise_app_store plugin helper!")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'cgi'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class UserResponse
|
|
8
|
+
attr_accessor :accessToken
|
|
9
|
+
|
|
10
|
+
def initialize(accessToken:)
|
|
11
|
+
@accessToken = accessToken
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module AuthService
|
|
16
|
+
def self.get_ac_token(pat:)
|
|
17
|
+
endpoint_url = 'https://auth.appcircle.io/auth/v2/token'
|
|
18
|
+
uri = URI(endpoint_url)
|
|
19
|
+
|
|
20
|
+
# Create HTTP request
|
|
21
|
+
request = Net::HTTP::Post.new(uri)
|
|
22
|
+
request.content_type = 'application/x-www-form-urlencoded'
|
|
23
|
+
request['Accept'] = 'application/json'
|
|
24
|
+
|
|
25
|
+
# Encode parameters
|
|
26
|
+
params = { pat: pat }
|
|
27
|
+
request.body = URI.encode_www_form(params)
|
|
28
|
+
|
|
29
|
+
# Make the HTTP request
|
|
30
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
|
31
|
+
http.request(request)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Check response
|
|
37
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
38
|
+
response_data = JSON.parse(response.body)
|
|
39
|
+
|
|
40
|
+
user = UserResponse.new(
|
|
41
|
+
accessToken: response_data['access_token']
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return user
|
|
45
|
+
else
|
|
46
|
+
raise "HTTP Request failed (#{response.code} #{response.message})"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'rest-client'
|
|
5
|
+
|
|
6
|
+
BASE_URL = "https://api.appcircle.io"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module UploadService
|
|
10
|
+
def self.upload_artifact(token:, app:)
|
|
11
|
+
url = "https://api.appcircle.io/store/v2/profiles/app-versions"
|
|
12
|
+
headers = {
|
|
13
|
+
Authorization: "Bearer #{token}",
|
|
14
|
+
content_type: :multipart
|
|
15
|
+
}
|
|
16
|
+
payload = {
|
|
17
|
+
File: File.new(app, 'rb')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
response = RestClient.post(url, payload, headers)
|
|
22
|
+
JSON.parse(response.body) rescue response.body
|
|
23
|
+
rescue RestClient::ExceptionWithResponse => e
|
|
24
|
+
raise e
|
|
25
|
+
rescue StandardError => e
|
|
26
|
+
raise e
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.getAppVersions(auth_token:, entProfileId:)
|
|
31
|
+
url = "#{BASE_URL}/store/v2/profiles/#{entProfileId}/app-versions"
|
|
32
|
+
|
|
33
|
+
# Set up the headers with authentication
|
|
34
|
+
headers = {
|
|
35
|
+
Authorization: "Bearer #{auth_token}",
|
|
36
|
+
accept: 'application/json'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
response = RestClient.get(url, headers)
|
|
41
|
+
parsed_response = JSON.parse(response.body)
|
|
42
|
+
|
|
43
|
+
parsed_response
|
|
44
|
+
rescue RestClient::ExceptionWithResponse => e
|
|
45
|
+
raise e
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
raise e
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.getVersionId(versionList:)
|
|
52
|
+
begin
|
|
53
|
+
if versionList.is_a?(Array) && !versionList.empty?
|
|
54
|
+
return versionList[0]["id"]
|
|
55
|
+
else
|
|
56
|
+
return nil
|
|
57
|
+
end
|
|
58
|
+
rescue => e
|
|
59
|
+
puts "An error occurred while getting app versions: #{e.message}"
|
|
60
|
+
raise e
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.publishVersion(options)
|
|
65
|
+
endpoint = "store/v2/profiles/#{options[:ent_profile_id]}/app-versions/#{options[:ent_version_id]}?action=publish"
|
|
66
|
+
url = "#{BASE_URL}/#{endpoint}"
|
|
67
|
+
|
|
68
|
+
payload = {
|
|
69
|
+
summary: options[:summary],
|
|
70
|
+
releaseNotes: options[:release_notes],
|
|
71
|
+
publishType: options[:publish_type]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
headers = {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
'Authorization': "Bearer #{options[:auth_token]}"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
response = RestClient.patch(url, payload.to_json, headers)
|
|
80
|
+
JSON.parse(response.body)
|
|
81
|
+
rescue RestClient::ExceptionWithResponse => e
|
|
82
|
+
raise e
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.getEntProfiles(authToken:)
|
|
86
|
+
url = "#{BASE_URL}/store/v2/profiles?Sort=desc"
|
|
87
|
+
headers = {
|
|
88
|
+
Authorization: "Bearer #{authToken}",
|
|
89
|
+
accept: 'application/json'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
response = RestClient.get(url, headers)
|
|
94
|
+
parsed_response = JSON.parse(response.body)
|
|
95
|
+
|
|
96
|
+
parsed_response
|
|
97
|
+
rescue RestClient::ExceptionWithResponse => e
|
|
98
|
+
raise e
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
raise e
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.getProfileId(authToken:)
|
|
105
|
+
profiles = self.getEntProfiles(authToken: authToken)
|
|
106
|
+
sortedProfiles = profiles.sort_by { |profile| DateTime.parse(profile["lastBinaryReceivedDate"]) }.reverse
|
|
107
|
+
|
|
108
|
+
return sortedProfiles[0]['id']
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'fastlane/plugin/appcircle_enterprise_app_store/version'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module AppcircleEnterpriseAppStore
|
|
5
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
|
6
|
+
def self.all_classes
|
|
7
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# By default we want to import all available actions and helpers
|
|
13
|
+
# A plugin can contain any number of actions and plugins
|
|
14
|
+
Fastlane::AppcircleEnterpriseAppStore.all_classes.each do |current|
|
|
15
|
+
require current
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fastlane-plugin-appcircle_enterprise_app_store
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- appcircleio
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-09-04 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rest-client
|
|
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
|
+
description:
|
|
28
|
+
email: cloud@appcircle.io
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- LICENSE
|
|
34
|
+
- README.md
|
|
35
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store.rb
|
|
36
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store/actions/appcircle_enterprise_app_store_action.rb
|
|
37
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store/helper/appcircle_enterprise_app_store_helper.rb
|
|
38
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store/helper/auth_service.rb
|
|
39
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store/helper/upload_service.rb
|
|
40
|
+
- lib/fastlane/plugin/appcircle_enterprise_app_store/version.rb
|
|
41
|
+
homepage: https://github.com/appcircleio/fastlane-plugin-appcircle_enterprise_app_store
|
|
42
|
+
licenses:
|
|
43
|
+
- MIT
|
|
44
|
+
metadata:
|
|
45
|
+
rubygems_mfa_required: 'false'
|
|
46
|
+
post_install_message:
|
|
47
|
+
rdoc_options: []
|
|
48
|
+
require_paths:
|
|
49
|
+
- lib
|
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '2.6'
|
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
60
|
+
requirements: []
|
|
61
|
+
rubygems_version: 3.4.10
|
|
62
|
+
signing_key:
|
|
63
|
+
specification_version: 4
|
|
64
|
+
summary: Efficiently publish your apps to Appcircle Enterprise Store
|
|
65
|
+
test_files: []
|