fastlane-plugin-nico 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 259c370e91a20c3cd611d0c7c177e77e8513d5e1d9e3475cdb95b5f3371549e6
4
+ data.tar.gz: 243639ffeb90a983f58a92d3e8662bfaf8878af2217cb0077f2fc9349994ed9e
5
+ SHA512:
6
+ metadata.gz: aee24183a3debfd3c4b99612737426f8047df98bdb9bf9111aabf9dae35f2a5862d7a9aea1a516fc19a1a1074196b29056063ab8f6beb06965cf99db4a434645
7
+ data.tar.gz: 7b5cad5c552acde4ff08d1415be04540337f74224117c4bd6ee30e5d12dedc97a6d48a2d6a274f56d4bc718d0df580422f1cf02c8de86581544a7d15e1f71b13
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Noah Martin <noahm444@gmail.com>
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,100 @@
1
+ # Emerge `fastlane` plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-emerge)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-emerge`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin emerge
11
+ ```
12
+
13
+ ## About Emerge
14
+
15
+ [Emerge](https://emergetools.com) offers a suite of products to help optimize app size, performance and quality. This plugin provides a set of actions to interact with the Emerge API.
16
+
17
+ ## Usage
18
+
19
+ To get started, first obtain an [API token](https://docs.emergetools.com/docs/uploading-basics#obtain-an-api-key) for your organization. The API Token is used to authenticate with the Emerge API in each call. Our actions will automatically pick up the API key if configured as an `EMERGE_API_TOKEN` environment variable.
20
+
21
+ ### Size Analysis
22
+
23
+ ```ruby
24
+ platform :ios do
25
+ lane :emerge_upload do
26
+ # Tip: group builds in our dashboard via the `tag` parameter
27
+ emerge(tag: 'pr_build')
28
+ end
29
+ end
30
+ ```
31
+
32
+ 1. Produce a build using `gym()`, `run_tests()`, or other Fastlane actions
33
+ 2. When you are ready to upload to Emerge, simply call the `emerge()` action
34
+ - a. We will automatically detect the most recently built app to upload, or you can manually pass in a `file_path` parameter
35
+
36
+ For a full list of available parameters run `fastlane action emerge`.
37
+
38
+ ### Snapshot Testing
39
+
40
+ ```ruby
41
+ platform :ios do
42
+ lane :snapshot_testing do
43
+ # Call our `emerge_snapshot()` action with the respective scheme for
44
+ # us to build. We will generate a build with the recommended settings
45
+ # and upload to our API.
46
+ emerge_snapshot(scheme: 'Hacker News')
47
+ end
48
+ end
49
+ ```
50
+
51
+ For a full list of available parameters run `fastlane action emerge_snapshot`.
52
+
53
+ ## Git Configuration
54
+
55
+ For build comparisons to work, Emerge needs the appropriate Git `sha` and `base_sha` values set on each build. Emerge will automatically compare a build at `sha` against the build we find matching the `base_sha` for a given application id. We also recommend setting `pr_number`, `branch`, `repo_name`, and `previous_sha` for the best experience.
56
+
57
+ For example:
58
+
59
+ - `sha`: `pr-branch-commit-2`
60
+ - `base_sha`: `main-branch-commit-1`
61
+ - `previous_sha`: `pr-branch-commit-1`
62
+ - `pr_number`: `42`
63
+ - `branch`: `my-awesome-feature`
64
+ - `repo_name`: `EmergeTools/hackernews`
65
+
66
+ Will compare the size difference of your pull request changes.
67
+
68
+ This plugin will automatically configure Git values for you assuming certain Github workflow triggers:
69
+
70
+ ```yaml
71
+ on:
72
+ # Produce base builds with a 'sha' when commits are pushed to the main branch
73
+ push:
74
+ branches: [main]
75
+
76
+ # Produce branch comparison builds with `sha` and `base_sha` when commits are pushed
77
+ # to open pull requests
78
+ pull_request:
79
+ branches: [main]
80
+
81
+ ...
82
+ ```
83
+
84
+ If this doesn't cover your use-case, manually set the `sha` and `base_sha` values when calling the Emerge plugin.
85
+
86
+ ## Issues and Feedback
87
+
88
+ For any other issues and feedback about this plugin, please open a [GitHub issue](https://github.com/EmergeTools/fastlane-plugin-emerge/issues).
89
+
90
+ ## Troubleshooting
91
+
92
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
93
+
94
+ ## Using _fastlane_ Plugins
95
+
96
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
97
+
98
+ ## About _fastlane_
99
+
100
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,227 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/print_table'
3
+ require_relative '../helper/emerge_helper'
4
+ require_relative '../helper/git'
5
+ require_relative '../helper/github'
6
+ require 'pathname'
7
+ require 'tmpdir'
8
+ require 'json'
9
+ require 'fileutils'
10
+
11
+ module Fastlane
12
+ module Actions
13
+ class EmergeAction < Action
14
+ def self.run(params)
15
+ api_token = params[:api_token]
16
+
17
+ file_path = if params[:file_path]
18
+ UI.message("Using input file_path: #{file_path}")
19
+ params[:file_path]
20
+ elsif lane_context[SharedValues::XCODEBUILD_ARCHIVE]
21
+ UI.message("Using XCODEBUILD_ARCHIVE path")
22
+ lane_context[SharedValues::XCODEBUILD_ARCHIVE]
23
+ else
24
+ UI.message("Falling back to searching SCAN_DERIVED_DATA_PATH")
25
+ Dir.glob("#{lane_context[SharedValues::SCAN_DERIVED_DATA_PATH]}/Build/Products/Debug-iphonesimulator/*.app").first
26
+ end
27
+
28
+ git_params = Helper::EmergeHelper.make_git_params
29
+ pr_number = params[:pr_number] || git_params.pr_number
30
+ branch = params[:branch] || git_params.branch
31
+ sha = params[:sha] || params[:build_id] || git_params.sha
32
+ base_sha = params[:base_sha] || params[:base_build_id] || git_params.base_sha
33
+ previous_sha = params[:previous_sha] || git_params.previous_sha
34
+ repo_name = params[:repo_name] || git_params.repo_name
35
+ gitlab_project_id = params[:gitlab_project_id]
36
+ tag = params[:tag]
37
+ order_file_version = params[:order_file_version]
38
+ config_path = params[:config_path]
39
+
40
+ if file_path.nil? || !File.exist?(file_path)
41
+ UI.error("Invalid input file")
42
+ return false
43
+ else
44
+ UI.message("Using file_path: #{file_path}")
45
+ end
46
+ extension = File.extname(file_path)
47
+
48
+ # If the user provided a .app we will look for dsyms and package it into a zipped xcarchive
49
+ if extension == '.app'
50
+ absolute_path = Pathname.new(File.expand_path(file_path))
51
+ UI.message("A .app was provided, dSYMs will be looked for in #{absolute_path.dirname}")
52
+ Dir.mktmpdir do |d|
53
+ application_folder = "#{d}/archive.xcarchive/Products/Applications/"
54
+ dsym_folder = "#{d}/archive.xcarchive/dSYMs/"
55
+ FileUtils.mkdir_p(application_folder)
56
+ FileUtils.mkdir_p(dsym_folder)
57
+ if params[:linkmaps] && params[:linkmaps].length > 0
58
+ linkmap_folder = "#{d}/archive.xcarchive/Linkmaps/"
59
+ FileUtils.mkdir_p(linkmap_folder)
60
+ params[:linkmaps].each do |l|
61
+ FileUtils.cp(l, linkmap_folder)
62
+ end
63
+ end
64
+ Helper::EmergeHelper.copy_config(config_path, "#{d}/archive.xcarchive")
65
+ FileUtils.cp_r(file_path, application_folder)
66
+ copy_dsyms("#{absolute_path.dirname}/*.dsym", dsym_folder)
67
+ copy_dsyms("#{absolute_path.dirname}/*/*.dsym", dsym_folder)
68
+ Xcodeproj::Plist.write_to_path({ "NAME" => "Emerge Upload" }, "#{d}/archive.xcarchive/Info.plist")
69
+ file_path = "#{absolute_path.dirname}/archive.xcarchive.zip"
70
+ ZipAction.run(
71
+ path: "#{d}/archive.xcarchive",
72
+ symlinks: true,
73
+ output_path: file_path,
74
+ exclude: [],
75
+ include: []
76
+ )
77
+ UI.message("Archive generated at #{file_path}")
78
+ end
79
+ elsif extension == '.xcarchive'
80
+ zip_path = file_path + ".zip"
81
+ if params[:linkmaps] && params[:linkmaps].length > 0
82
+ linkmap_folder = "#{file_path}/Linkmaps/"
83
+ FileUtils.mkdir_p(linkmap_folder)
84
+ params[:linkmaps].each do |l|
85
+ FileUtils.cp(l, linkmap_folder)
86
+ end
87
+ end
88
+ Helper::EmergeHelper.copy_config(config_path, file_path)
89
+ Actions::ZipAction.run(
90
+ path: file_path,
91
+ symlinks: true,
92
+ output_path: zip_path,
93
+ exclude: [],
94
+ include: []
95
+ )
96
+ file_path = zip_path
97
+ elsif (extension == '.zip' || extension == '.ipa') && params[:linkmaps] && params[:linkmaps].length > 0
98
+ UI.error("Provided #{extension == '.zip' ? 'zipped archive' : 'ipa'} and linkmaps, linkmaps will not be added to upload.")
99
+ elsif extension != '.zip' && extension != '.ipa'
100
+ UI.error("Invalid input file")
101
+ return false
102
+ end
103
+
104
+ params = {
105
+ prNumber: pr_number,
106
+ branch: branch,
107
+ sha: sha,
108
+ baseSha: base_sha,
109
+ previousSha: previous_sha,
110
+ repoName: repo_name,
111
+ gitlabProjectId: gitlab_project_id,
112
+ orderFileVersion: order_file_version,
113
+ appIdSuffix: params[:app_id_suffix],
114
+ releaseNotes: params[:release_notes],
115
+ tag: tag || "default"
116
+ }
117
+ upload_id = Helper::EmergeHelper.perform_upload(api_token, params, file_path)
118
+ UI.success("🎉 Your app is processing, you can find the results at https://emergetools.com/build/#{upload_id}")
119
+ upload_id
120
+ end
121
+
122
+ def self.copy_dsyms(from, to)
123
+ Dir.glob(from) do |filename|
124
+ UI.message("Found dSYM: #{Pathname.new(filename).basename}")
125
+ FileUtils.cp_r(filename, to)
126
+ end
127
+ end
128
+
129
+ def self.description
130
+ "Fastlane plugin for Emerge"
131
+ end
132
+
133
+ def self.authors
134
+ ["Emerge Tools"]
135
+ end
136
+
137
+ def self.return_value
138
+ "If successful, returns the upload id of the generated build"
139
+ end
140
+
141
+ def self.details
142
+ ""
143
+ end
144
+
145
+ def self.available_options
146
+ [
147
+ FastlaneCore::ConfigItem.new(key: :api_token,
148
+ env_name: "EMERGE_API_TOKEN",
149
+ description: "An API token for Emerge",
150
+ optional: false,
151
+ type: String),
152
+ FastlaneCore::ConfigItem.new(key: :file_path,
153
+ env_name: "EMERGE_FILE_PATH",
154
+ description: "Path to the zipped xcarchive or app to upload",
155
+ optional: true,
156
+ type: String),
157
+ FastlaneCore::ConfigItem.new(key: :linkmaps,
158
+ description: "List of paths to linkmaps",
159
+ optional: true,
160
+ type: Array),
161
+ FastlaneCore::ConfigItem.new(key: :pr_number,
162
+ description: "The PR number that triggered this upload",
163
+ optional: true,
164
+ type: String),
165
+ FastlaneCore::ConfigItem.new(key: :branch,
166
+ description: "The current git branch",
167
+ optional: true,
168
+ type: String),
169
+ FastlaneCore::ConfigItem.new(key: :sha,
170
+ description: "The git SHA that triggered this build",
171
+ optional: true,
172
+ type: String),
173
+ FastlaneCore::ConfigItem.new(key: :base_sha,
174
+ description: "The git SHA of the base build",
175
+ optional: true,
176
+ type: String),
177
+ FastlaneCore::ConfigItem.new(key: :previous_sha,
178
+ description: "The git SHA of the commit right before this build's commit",
179
+ optional: true,
180
+ type: String),
181
+ FastlaneCore::ConfigItem.new(key: :build_id,
182
+ description: "A string to identify this build",
183
+ deprecated: "Replaced by `sha`",
184
+ optional: true,
185
+ type: String),
186
+ FastlaneCore::ConfigItem.new(key: :base_build_id,
187
+ description: "Id of the build to compare with this upload",
188
+ deprecated: "Replaced by `base_sha`",
189
+ optional: true,
190
+ type: String),
191
+ FastlaneCore::ConfigItem.new(key: :repo_name,
192
+ description: "Full name of the respository this upload was triggered from. For example: EmergeTools/Emerge",
193
+ optional: true,
194
+ type: String),
195
+ FastlaneCore::ConfigItem.new(key: :gitlab_project_id,
196
+ description: "Id of the gitlab project this upload was triggered from",
197
+ optional: true,
198
+ type: Integer),
199
+ FastlaneCore::ConfigItem.new(key: :tag,
200
+ description: "String to label the build. Useful for grouping builds together in our dashboard, like development, default, or pull-request",
201
+ optional: true,
202
+ type: String),
203
+ FastlaneCore::ConfigItem.new(key: :order_file_version,
204
+ description: "Version of the order file to download",
205
+ optional: true,
206
+ type: String),
207
+ FastlaneCore::ConfigItem.new(key: :config_path,
208
+ description: "Path to Emerge config path",
209
+ optional: true,
210
+ type: String),
211
+ FastlaneCore::ConfigItem.new(key: :app_id_suffix,
212
+ description: "A suffix to append to the application ID to differentiate between different builds of the same app",
213
+ optional: true,
214
+ type: String),
215
+ FastlaneCore::ConfigItem.new(key: :release_notes,
216
+ description: "A markdown string with release notes for the upload",
217
+ optional: true,
218
+ type: String)
219
+ ]
220
+ end
221
+
222
+ def self.is_supported?(platform)
223
+ platform == :ios
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,86 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/print_table'
3
+ require_relative '../helper/emerge_helper'
4
+
5
+ module Fastlane
6
+ module Actions
7
+ class EmergeComment < Action
8
+ def self.run(params)
9
+ url = 'https://api.emergetools.com/getComment'
10
+ api_token = params[:api_token]
11
+ gitlab_url = params[:gitlab_url]
12
+ project_id = params[:gitlab_project_id]
13
+ pr_number = params[:pr_number]
14
+ gitlab_access_token = params[:gitlab_access_token]
15
+
16
+ request_params = {
17
+ buildId: params[:build_id],
18
+ baseBuildId: params[:base_build_id]
19
+ }
20
+ resp = Faraday.get(url, request_params, 'x-api-token' => api_token)
21
+ case resp.status
22
+ when 200
23
+ UI.message("Received comment from Emerge")
24
+ baseURL = gitlab_url ? gitlab_url : "https://gitlab.com"
25
+ url = "#{baseURL}/api/v4/projects/#{project_id}/merge_requests/#{pr_number}/notes"
26
+ gitlab_response = Faraday.post(url, { "body" => resp.body }, 'Authorization' => "Bearer #{gitlab_access_token}")
27
+ case gitlab_response.status
28
+ when 200...299
29
+ UI.message("Successfully posted comment")
30
+ else
31
+ UI.error("Received error #{gitlab_response.status} from Gitlab")
32
+ end
33
+ else
34
+ UI.error("Received error #{resp.status} from Emerge")
35
+ end
36
+ end
37
+
38
+ def self.description
39
+ "Post an Emerge PR comment, currently supports Gitlab only."
40
+ end
41
+
42
+ def self.authors
43
+ ["Emerge Tools"]
44
+ end
45
+
46
+ def self.available_options
47
+ [
48
+ FastlaneCore::ConfigItem.new(key: :api_token,
49
+ env_name: "EMERGE_API_TOKEN",
50
+ description: "An API token for Emerge",
51
+ optional: false,
52
+ type: String),
53
+ FastlaneCore::ConfigItem.new(key: :gitlab_acces_token,
54
+ env_name: "GITLAB_ACCESS_TOKEN",
55
+ description: "An access token for Gitlab",
56
+ optional: false,
57
+ type: String),
58
+ FastlaneCore::ConfigItem.new(key: :pr_number,
59
+ description: "The PR number that triggered this upload",
60
+ optional: false,
61
+ type: String),
62
+ FastlaneCore::ConfigItem.new(key: :build_id,
63
+ description: "A string to identify this build",
64
+ optional: false,
65
+ type: String),
66
+ FastlaneCore::ConfigItem.new(key: :base_build_id,
67
+ description: "Id of the build to compare with this upload",
68
+ optional: false,
69
+ type: String),
70
+ FastlaneCore::ConfigItem.new(key: :gitlab_url,
71
+ description: "URL of the self hosted gitlab instance",
72
+ optional: true,
73
+ type: String),
74
+ FastlaneCore::ConfigItem.new(key: :gitlab_project_id,
75
+ description: "Id of the gitlab project this upload was triggered from",
76
+ optional: false,
77
+ type: Integer)
78
+ ]
79
+ end
80
+
81
+ def self.is_supported?(platform)
82
+ platform == :ios
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,77 @@
1
+ require 'fastlane/action'
2
+ require 'tmpdir'
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+
6
+ module Fastlane
7
+ module Actions
8
+ class EmergeOrderFileAction < Action
9
+ def self.run(params)
10
+ puts "https://order-files-prod.emergetools.com/#{params[:app_id]}/#{params[:order_file_version]}"
11
+ resp = Faraday.get("https://order-files-prod.emergetools.com/#{params[:app_id]}/#{params[:order_file_version]}", nil, {'X-API-Token' => params[:api_token]})
12
+ case resp.status
13
+ when 200
14
+ Tempfile.create do |f|
15
+ f.write(resp.body)
16
+ decompressed = IO.popen(['gunzip', '-c', f.path]).read
17
+ IO.write(params[:output_path], decompressed)
18
+ end
19
+ return 200
20
+ when 401
21
+ UI.error("Unauthorized")
22
+ when 403
23
+ UI.message("No order file found, this is expected for the first build of an app_id/version.")
24
+ # The API will return a 403 when no order file is found, but we change that to a 200 for the
25
+ # fastlane plugin because this is an expected state for a CI integraion.
26
+ return 200
27
+ else
28
+ UI.error("Failed to download order file code: #{resp.status}")
29
+ end
30
+ resp.status
31
+ end
32
+
33
+ def self.description
34
+ "Fastlane plugin to download order files"
35
+ end
36
+
37
+ def self.authors
38
+ ["Emerge Tools"]
39
+ end
40
+
41
+ def self.return_value
42
+ # If your method provides a return value, you can describe here what it does
43
+ end
44
+
45
+ def self.details
46
+ # Optional:
47
+ ""
48
+ end
49
+
50
+ def self.available_options
51
+ [
52
+ FastlaneCore::ConfigItem.new(key: :api_token,
53
+ env_name: "EMERGE_API_TOKEN",
54
+ description: "An API token for Emerge",
55
+ optional: false,
56
+ type: String),
57
+ FastlaneCore::ConfigItem.new(key: :app_id,
58
+ description: "Id of the app being built with the order file",
59
+ optional: false,
60
+ type: String),
61
+ FastlaneCore::ConfigItem.new(key: :output_path,
62
+ description: "Path to the order file",
63
+ optional: false,
64
+ type: String),
65
+ FastlaneCore::ConfigItem.new(key: :order_file_version,
66
+ description: "Version of the order file to download",
67
+ optional: false,
68
+ type: String),
69
+ ]
70
+ end
71
+
72
+ def self.is_supported?(platform)
73
+ platform == :ios
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,162 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/print_table'
3
+ require_relative '../helper/emerge_helper'
4
+ require_relative '../helper/git'
5
+ require_relative '../helper/github'
6
+ require 'pathname'
7
+ require 'tmpdir'
8
+ require 'json'
9
+ require 'fileutils'
10
+
11
+ module Fastlane
12
+ module Actions
13
+ class EmergeSnapshotAction < Action
14
+ def self.run(params)
15
+ api_token = params[:api_token]
16
+
17
+ git_params = Helper::EmergeHelper.make_git_params
18
+ pr_number = params[:pr_number] || git_params.pr_number
19
+ branch = params[:branch] || git_params.branch
20
+ sha = params[:sha] || git_params.sha
21
+ base_sha = params[:base_sha] || git_params.base_sha
22
+ previous_sha = params[:previous_sha] || git_params.previous_sha
23
+ repo_name = params[:repo_name] || git_params.repo_name
24
+ gitlab_project_id = params[:gitlab_project_id]
25
+ tag = params[:tag]
26
+ config_path = params[:config_path]
27
+ scheme = params[:scheme]
28
+ configuration = params[:configuration]
29
+ team_id = params[:team_id] || CredentialsManager::AppfileConfig.try_fetch_value(:team_id)
30
+
31
+ Dir.mktmpdir do |temp_dir|
32
+ archive_name = "#{scheme}-Emerge-Snapshots"
33
+ archive_path = "#{temp_dir}/build/#{archive_name}.xcarchive"
34
+ make_debug_build(
35
+ scheme: scheme,
36
+ configuration: configuration,
37
+ team_id: team_id,
38
+ archive_path: archive_path
39
+ )
40
+ Helper::EmergeHelper.copy_config(config_path, archive_path)
41
+ Xcodeproj::Plist.write_to_path({ "NAME" => "Emerge Upload" }, "#{archive_path}/Info.plist")
42
+
43
+ zip_file_path = "#{temp_dir}/build/#{archive_name}.xcarchive.zip"
44
+ ZipAction.run(
45
+ path: archive_path,
46
+ symlinks: true,
47
+ output_path: zip_file_path,
48
+ exclude: [],
49
+ include: []
50
+ )
51
+
52
+ params = {
53
+ appIdSuffix: 'snapshots',
54
+ prNumber: pr_number,
55
+ branch: branch,
56
+ sha: sha,
57
+ baseSha: base_sha,
58
+ previousSha: previous_sha,
59
+ repoName: repo_name,
60
+ gitlabProjectId: gitlab_project_id,
61
+ tag: tag || "default"
62
+ }
63
+ upload_id = Helper::EmergeHelper.perform_upload(api_token, params, zip_file_path)
64
+ UI.success("🎉 Your app is processing, you can find the results at https://emergetools.com/snapshot/#{upload_id}")
65
+ end
66
+ end
67
+
68
+ def self.make_debug_build(scheme:, configuration:, team_id:, archive_path:)
69
+ other_action.gym(
70
+ scheme: scheme,
71
+ configuration: configuration,
72
+ skip_codesigning: true,
73
+ clean: true,
74
+ export_method: "development",
75
+ export_team_id: team_id,
76
+ skip_package_ipa: true,
77
+ archive_path: archive_path
78
+ )
79
+ end
80
+
81
+ def self.description
82
+ "Fastlane plugin for Emerge to generate iOS snapshots"
83
+ end
84
+
85
+ def self.authors
86
+ ["Emerge Tools"]
87
+ end
88
+
89
+ def self.return_value
90
+ "If successful, returns the upload id of the generated snapshot build"
91
+ end
92
+
93
+ def self.details
94
+ ""
95
+ end
96
+
97
+ def self.available_options
98
+ [
99
+ FastlaneCore::ConfigItem.new(key: :api_token,
100
+ env_name: "EMERGE_API_TOKEN",
101
+ description: "An API token for Emerge",
102
+ optional: false,
103
+ type: String),
104
+ FastlaneCore::ConfigItem.new(key: :scheme,
105
+ description: "The scheme of your app to build",
106
+ optional: false,
107
+ type: String),
108
+ FastlaneCore::ConfigItem.new(key: :configuration,
109
+ description: "The configuration of your app to use",
110
+ optional: false,
111
+ default_value: "Debug",
112
+ type: String),
113
+ FastlaneCore::ConfigItem.new(key: :team_id,
114
+ env_name: "EXPORT_TEAM_ID",
115
+ description: "The Apple Team ID to use for exporting the archive. If not provided, we will try to use the team_id from the Appfile",
116
+ optional: true,
117
+ type: String),
118
+ FastlaneCore::ConfigItem.new(key: :config_path,
119
+ description: "Path to Emerge YAML config path",
120
+ optional: true,
121
+ type: String),
122
+ FastlaneCore::ConfigItem.new(key: :pr_number,
123
+ description: "The PR number that triggered this upload",
124
+ optional: true,
125
+ type: String),
126
+ FastlaneCore::ConfigItem.new(key: :branch,
127
+ description: "The current git branch",
128
+ optional: true,
129
+ type: String),
130
+ FastlaneCore::ConfigItem.new(key: :sha,
131
+ description: "The git SHA that triggered this build",
132
+ optional: true,
133
+ type: String),
134
+ FastlaneCore::ConfigItem.new(key: :base_sha,
135
+ description: "The git SHA of the base build",
136
+ optional: true,
137
+ type: String),
138
+ FastlaneCore::ConfigItem.new(key: :previous_sha,
139
+ description: "The git SHA of the commit right before this build's commit",
140
+ optional: true,
141
+ type: String),
142
+ FastlaneCore::ConfigItem.new(key: :repo_name,
143
+ description: "Full name of the respository this upload was triggered from. For example: EmergeTools/Emerge",
144
+ optional: true,
145
+ type: String),
146
+ FastlaneCore::ConfigItem.new(key: :gitlab_project_id,
147
+ description: "Id of the gitlab project this upload was triggered from",
148
+ optional: true,
149
+ type: Integer),
150
+ FastlaneCore::ConfigItem.new(key: :tag,
151
+ description: "String to label the build. Useful for grouping builds together in our dashboard, like development, default, or pull-request",
152
+ optional: true,
153
+ type: String)
154
+ ]
155
+ end
156
+
157
+ def self.is_supported?(platform)
158
+ platform == :ios
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,140 @@
1
+ require 'fastlane_core/ui/ui'
2
+ require 'faraday'
3
+
4
+ module Fastlane
5
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
6
+
7
+ class GitResult
8
+ attr_accessor :sha, :base_sha, :previous_sha, :branch, :pr_number, :repo_name
9
+
10
+ def initialize(sha:, base_sha:, previous_sha:, branch:, pr_number: nil, repo_name: nil)
11
+ @pr_number = pr_number
12
+ @sha = sha
13
+ @base_sha = base_sha
14
+ @previous_sha = previous_sha
15
+ @branch = branch
16
+ @repo_name = repo_name
17
+ end
18
+ end
19
+
20
+ module Helper
21
+ class EmergeHelper
22
+ API_URL = 'https://api.emergetools.com/upload'.freeze
23
+
24
+ def self.perform_upload(api_token, params, file_path)
25
+ cleaned_params = clean_params(params)
26
+ print_summary(cleaned_params)
27
+
28
+ upload_response = create_upload(api_token, cleaned_params)
29
+ handle_upload_response(api_token, upload_response, file_path)
30
+ rescue StandardError => e
31
+ UI.user_error!(e.message)
32
+ end
33
+
34
+ def self.make_git_params
35
+ git_result = if Helper::Github.is_supported_github_event?
36
+ UI.message("Fetching Git info from Github event. This is what we get")
37
+ UI.message("Github previous_sha: #{Helper::Github.previous_sha}")
38
+ UI.message("Git previous_sha: #{Helper::Git.previous_sha}")
39
+ UI.message("Ok for real going to fetch")
40
+ GitResult.new(
41
+ sha: Helper::Github.sha,
42
+ base_sha: Helper::Github.base_sha,
43
+ previous_sha: Helper::Github.previous_sha,
44
+ branch: Helper::Github.branch,
45
+ pr_number: Helper::Github.pr_number,
46
+ repo_name: Helper::Github.repo_name
47
+ )
48
+ else
49
+ UI.message("Fetching Git info from system Git")
50
+ GitResult.new(
51
+ sha: Helper::Git.sha,
52
+ base_sha: Helper::Git.base_sha,
53
+ previous_sha: Helper::Git.previous_sha,
54
+ branch: Helper::Git.branch
55
+ )
56
+ end
57
+ UI.message("Got git result #{git_result.inspect}")
58
+ git_result
59
+ end
60
+
61
+ def self.copy_config(config_path, tmp_dir)
62
+ return if config_path.nil?
63
+
64
+ expanded_path = File.expand_path(config_path)
65
+ unless File.exist?(expanded_path)
66
+ UI.error("No config file found at path '#{expanded_path}'.\nUploading without config file")
67
+ return
68
+ end
69
+
70
+ emerge_config_path = "#{tmp_dir}/emerge_config.yaml"
71
+ FileUtils.cp(expanded_path, emerge_config_path)
72
+ end
73
+
74
+ private_class_method
75
+
76
+ def self.clean_params(params)
77
+ params.reject { |_, v| v.nil? }
78
+ end
79
+
80
+ def self.print_summary(params)
81
+ FastlaneCore::PrintTable.print_values(
82
+ config: params,
83
+ hide_keys: [],
84
+ title: "Summary for Emerge Upload #{Fastlane::Emerge::VERSION}"
85
+ )
86
+ end
87
+
88
+ def self.create_upload(api_token, params)
89
+ response = Faraday.post(API_URL, params.to_json, headers(api_token, params, 'application/json'))
90
+ parse_response(response)
91
+ end
92
+
93
+ def self.headers(api_token, params, content_type)
94
+ {
95
+ 'Content-Type' => content_type,
96
+ 'X-API-Token' => api_token,
97
+ 'User-Agent' => "fastlane-plugin-nico/#{Fastlane::Emerge::VERSION}"
98
+ }
99
+ end
100
+
101
+ def self.parse_response(response)
102
+ case response.status
103
+ when 200
104
+ JSON.parse(response.body)
105
+ when 400
106
+ error_message = JSON.parse(response.body)['errorMessage']
107
+ raise "Invalid parameters: #{error_message}"
108
+ when 401, 403
109
+ raise 'Invalid API token'
110
+ else
111
+ raise "Creating upload failed with status #{response.status}"
112
+ end
113
+ end
114
+
115
+ def self.handle_upload_response(api_token, response, file_path)
116
+ upload_url = response.fetch('uploadURL')
117
+ upload_id = response.fetch('upload_id')
118
+
119
+ warning = response.dig('warning')
120
+ if warning
121
+ UI.important(warning)
122
+ end
123
+
124
+ UI.message('Starting zip file upload')
125
+ upload_file(api_token, upload_url, file_path)
126
+ upload_id
127
+ end
128
+
129
+ def self.upload_file(api_token, upload_url, file_path)
130
+ response = Faraday.put(upload_url) do |req|
131
+ req.headers = headers(api_token, nil, 'application/zip')
132
+ req.headers['Content-Length'] = File.size(file_path).to_s
133
+ req.body = Faraday::UploadIO.new(file_path, 'application/zip')
134
+ end
135
+
136
+ raise "Uploading zip file failed #{response.status}" unless response.status == 200
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,106 @@
1
+ require 'fastlane_core/print_table'
2
+ require 'open3'
3
+
4
+ module Fastlane
5
+ module Helper
6
+ module Git
7
+ def self.branch
8
+ shell_command = "git rev-parse --abbrev-ref HEAD"
9
+ UI.command(shell_command)
10
+ stdout, _, status = Open3.capture3(shell_command)
11
+ unless status.success?
12
+ UI.error("Failed to get the current branch name")
13
+ return nil
14
+ end
15
+
16
+ branch_name = stdout.strip
17
+ if branch_name == "HEAD"
18
+ # We're in a detached HEAD state
19
+ # Find all branches that contains the current HEAD commit
20
+ #
21
+ # Example output:
22
+ # * (HEAD detached at dec13a5)
23
+ # telkins/detached-test
24
+ # remotes/origin/telkins/detached-test
25
+ #
26
+ # So far I've seen this output be fairly stable
27
+ # If the input is invalid for whatever reason, sed/awk will return an empty string
28
+ shell_command = "git branch -a --contains HEAD | sed -n 2p | awk '{ printf $1 }'"
29
+ UI.command(shell_command)
30
+ head_stdout, _, head_status = Open3.capture3(shell_command)
31
+
32
+ unless head_status.success?
33
+ UI.error("Failed to get the current branch name for detached HEAD")
34
+ return nil
35
+ end
36
+
37
+ branch_name = head_stdout.strip
38
+ end
39
+
40
+ branch_name == "HEAD" ? nil : branch_name
41
+ end
42
+
43
+ def self.sha
44
+ shell_command = "git rev-parse HEAD"
45
+ UI.command(shell_command)
46
+ stdout, _, status = Open3.capture3(shell_command)
47
+ stdout.strip if status.success?
48
+ end
49
+
50
+ def self.base_sha
51
+ current_branch = branch
52
+ remote_head = remote_head_branch
53
+ return nil if current_branch.nil? || remote_head.nil?
54
+
55
+ shell_command = "git merge-base #{remote_head} #{current_branch}"
56
+ UI.command(shell_command)
57
+ stdout, _, status = Open3.capture3(shell_command)
58
+ return nil if stdout.strip.empty? || !status.success?
59
+ current_sha = sha
60
+ stdout.strip == current_sha ? nil : stdout.strip
61
+ end
62
+
63
+ def self.previous_sha
64
+ shell_command = "git rev-parse HEAD^"
65
+ UI.command(shell_command)
66
+ stdout, _, status = Open3.capture3(shell_command)
67
+ stdout.strip if status.success?
68
+ end
69
+
70
+ def self.primary_remote
71
+ remote = remote()
72
+ return nil if remote.nil?
73
+ remote.include?("origin") ? "origin" : remote.first
74
+ end
75
+
76
+ def self.remote_head_branch(remote = primary_remote)
77
+ return nil if remote.nil?
78
+ shell_command = "git remote show #{remote}"
79
+ UI.command(shell_command)
80
+ stdout, _, status = Open3.capture3(shell_command)
81
+ return nil if stdout.nil? || !status.success?
82
+ stdout
83
+ .split("\n")
84
+ .map(&:strip)
85
+ .find { |line| line.start_with?("HEAD branch: ") }
86
+ &.split(' ')
87
+ &.last
88
+ end
89
+
90
+ def self.remote_url(remote = primary_remote)
91
+ return nil if remote.nil?
92
+ shell_command = "git config --get remote.#{remote}.url"
93
+ UI.command(shell_command)
94
+ stdout, _, status = Open3.capture3(shell_command)
95
+ stdout if status.success?
96
+ end
97
+
98
+ def self.remote
99
+ shell_command = "git remote"
100
+ UI.command(shell_command)
101
+ stdout, _, status = Open3.capture3(shell_command)
102
+ stdout.split("\n") if status.success?
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,88 @@
1
+ require 'json'
2
+ require 'fastlane_core/print_table'
3
+ require_relative 'git'
4
+
5
+ module Fastlane
6
+ module Helper
7
+ module Github
8
+ GITHUB_EVENT_PR = "pull_request".freeze
9
+ GITHUB_EVENT_PUSH = "push".freeze
10
+
11
+ def self.event_name
12
+ ENV['GITHUB_EVENT_NAME']
13
+ end
14
+
15
+ def self.is_supported_github_event?
16
+ UI.message("GitHub event name: #{event_name}")
17
+ is_pull_request? || is_push?
18
+ end
19
+
20
+ def self.is_pull_request?
21
+ event_name == GITHUB_EVENT_PR
22
+ end
23
+
24
+ def self.is_push?
25
+ event_name == GITHUB_EVENT_PUSH
26
+ end
27
+
28
+ def self.sha
29
+ if is_push?
30
+ ENV['GITHUB_SHA']
31
+ elsif is_pull_request?
32
+ github_event_data.dig(:pull_request, :head, :sha)
33
+ end
34
+ end
35
+
36
+ def self.base_sha
37
+ if is_pull_request?
38
+ github_event_data.dig(:pull_request, :base, :sha)
39
+ end
40
+ end
41
+
42
+ def self.previous_sha
43
+ if is_push?
44
+ github_event_data.dig(:before)
45
+ else
46
+ shell_command = "git rev-parse HEAD^"
47
+ UI.command(shell_command)
48
+ stdout, _, status = Open3.capture3(shell_command)
49
+ stdout.strip if status.success?
50
+ end
51
+ end
52
+
53
+ def self.pr_number
54
+ is_pull_request? ? github_event_data.dig(:number) : nil
55
+ end
56
+
57
+ def self.branch
58
+ is_pull_request? ? github_event_data.dig(:pull_request, :head, :ref) : Git.branch
59
+ end
60
+
61
+ def self.repo_owner
62
+ github_event_data.dig(:repository, :owner, :login)
63
+ end
64
+
65
+ def self.repo_name
66
+ github_event_data.dig(:repository, :full_name)
67
+ end
68
+
69
+ private_class_method
70
+
71
+ def self.github_event_data
72
+ github_event_path = ENV['GITHUB_EVENT_PATH']
73
+ UI.error!("GITHUB_EVENT_PATH is not set") if github_event_path.nil?
74
+
75
+ unless File.exist?(github_event_path)
76
+ UI.error!("File #{github_event_path} doesn't exist")
77
+ end
78
+
79
+ file_content = File.read(github_event_path)
80
+ file_json = JSON.parse(file_content, symbolize_names: true)
81
+ if ENV['DEBUG']
82
+ UI.message("Parsed GitHub event data: #{file_json.inspect}")
83
+ end
84
+ file_json
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Emerge
3
+ VERSION = "0.10.6"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/emerge/version'
2
+
3
+ module Fastlane
4
+ module Emerge
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::Emerge.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-nico
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.6
5
+ platform: ruby
6
+ authors:
7
+ - Nico Testing
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec_junit_formatter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.49.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.49.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-require_tools
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: fastlane
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 2.170.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 2.170.0
153
+ description:
154
+ email:
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - LICENSE
160
+ - README.md
161
+ - lib/fastlane/plugin/emerge.rb
162
+ - lib/fastlane/plugin/emerge/actions/emerge_action.rb
163
+ - lib/fastlane/plugin/emerge/actions/emerge_comment_action.rb
164
+ - lib/fastlane/plugin/emerge/actions/emerge_order_file_action.rb
165
+ - lib/fastlane/plugin/emerge/actions/emerge_snapshot_action.rb
166
+ - lib/fastlane/plugin/emerge/helper/emerge_helper.rb
167
+ - lib/fastlane/plugin/emerge/helper/git.rb
168
+ - lib/fastlane/plugin/emerge/helper/github.rb
169
+ - lib/fastlane/plugin/emerge/version.rb
170
+ homepage: https://github.com/EmergeTools/fastlane-plugin-emerge
171
+ licenses:
172
+ - MIT
173
+ metadata: {}
174
+ post_install_message:
175
+ rdoc_options: []
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ requirements: []
189
+ rubygems_version: 3.5.21
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: Fastlane plugin for Emerge
193
+ test_files: []