emerge 0.2.1 → 0.2.2
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/README.md +22 -1
- data/lib/commands/config/orderfiles/orderfiles_ios.rb +0 -2
- data/lib/commands/config/snapshots/snapshots_ios.rb +5 -8
- data/lib/commands/integrate/fastlane.rb +2 -2
- data/lib/commands/upload/snapshots/snapshots.rb +4 -4
- data/lib/emerge_cli.rb +25 -19
- data/lib/reaper/ast_parser.rb +234 -0
- data/lib/utils/git.rb +1 -1
- data/lib/utils/github.rb +3 -3
- data/lib/utils/logger.rb +2 -2
- data/lib/utils/network.rb +23 -8
- data/lib/version.rb +2 -2
- metadata +25 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a44399f9df18a4ce4d32984e12eaadb2fa921c34409d8e4daa0dd1b4acddd2c
|
4
|
+
data.tar.gz: 855d965c1478cbc23eee27f5f99281d1a144b7c40197bdb693fac7d93f0be72d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d005834cf05f3d463df75af935e5e5ad075fe98cac3a05169df0e9f29c50366731f99b606af924ec33afce6fe332cd0e0ebccdd4768d52fa2dff59628e28b68
|
7
|
+
data.tar.gz: 184aad1844eacdf8aa3693ab5ff45acb36f11a16d039f258137f807f355f822b5f31565450927f5b6db453300785df287dcb5dc7c68227d635ccc7dc498a83ba
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@ gem install emerge
|
|
14
14
|
|
15
15
|
## API Key
|
16
16
|
|
17
|
-
Follow our guide to obtain an [API key](https://docs.emergetools.com/docs/uploading-basics#obtain-an-api-key) for your organization. The API Token is used by the CLI to authenticate with the Emerge API. The CLI will automatically pick up the API key if configured as an `EMERGE_API_TOKEN` environment variable, or you can manually pass it into individual commands.
|
17
|
+
Follow our guide to obtain an [API key](https://docs.emergetools.com/docs/uploading-basics#obtain-an-api-key) for your organization. The API Token is used by the CLI to authenticate with the Emerge API. The CLI will automatically pick up the API key if configured as an `EMERGE_API_TOKEN` environment variable, or you can manually pass it into individual commands with the `--api-token` option.
|
18
18
|
|
19
19
|
## Snapshots
|
20
20
|
|
@@ -92,3 +92,24 @@ emerge upload snapshots \
|
|
92
92
|
--client-library paparazzi \
|
93
93
|
--project-root /my/awesomeapp/android/repo
|
94
94
|
```
|
95
|
+
|
96
|
+
### Using with Roborazzi
|
97
|
+
|
98
|
+
Snapshots generated via [Roborazzi](https://github.com/takahirom/roborazzi) are natively supported by the CLI by setting `--client-library roborazzi` and a `--project-root` directory. This will scan your project for all images found in `**/build/outputs/roborazzi` directories.
|
99
|
+
|
100
|
+
Example:
|
101
|
+
|
102
|
+
```shell
|
103
|
+
emerge upload snapshots \
|
104
|
+
--name "AwesomeApp Roborazzi" \
|
105
|
+
--id "com.emerge.awesomeapp.roborazzi" \
|
106
|
+
--repo-name "EmergeTools/AwesomeApp" \
|
107
|
+
--client-library roborazzi \
|
108
|
+
--project-root /my/awesomeapp/android/repo
|
109
|
+
```
|
110
|
+
|
111
|
+
## Building
|
112
|
+
|
113
|
+
This depends on [Tree Sitter](https://tree-sitter.github.io/tree-sitter/) for part of its functionality.
|
114
|
+
|
115
|
+
In order to parse language grammars for Swift and Kotlin, both of which are third-party language grammars, we also depend on [tsdl](https://github.com/stackmystack/tsdl). This downloads and compiles the language grammars into dylibs for us to use.
|
@@ -39,8 +39,6 @@ module EmergeCLI
|
|
39
39
|
format KEY=VALUE".freeze
|
40
40
|
AVAILABLE_OS_VERSIONS = ['17.2', '17.5', '18.0'].freeze
|
41
41
|
|
42
|
-
def initialize; end
|
43
|
-
|
44
42
|
def call(**options)
|
45
43
|
@options = options
|
46
44
|
before(options)
|
@@ -204,12 +202,11 @@ format KEY=VALUE".freeze
|
|
204
202
|
end
|
205
203
|
|
206
204
|
def get_parsed_previews(previews_exact, previews_regex)
|
207
|
-
excluded =
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
})
|
205
|
+
excluded = previews_exact.map do |preview|
|
206
|
+
{
|
207
|
+
'type' => 'exact',
|
208
|
+
'value' => preview
|
209
|
+
}
|
213
210
|
end
|
214
211
|
previews_regex.each do |preview|
|
215
212
|
excluded.push({
|
@@ -80,7 +80,7 @@ module EmergeCLI
|
|
80
80
|
|
81
81
|
# Add app_size lane if not present
|
82
82
|
unless current_content.match?(/^\s*lane\s*:app_size\s*do/)
|
83
|
-
app_size_lane = <<~
|
83
|
+
app_size_lane = <<~RUBY.gsub(/^/, ' ')
|
84
84
|
lane :app_size do
|
85
85
|
# NOTE: If you already have a lane setup to build your app, then you can that instead of this and call emerge() after it.
|
86
86
|
build_app(scheme: ENV["SCHEME_NAME"], export_method: "development")
|
@@ -92,7 +92,7 @@ module EmergeCLI
|
|
92
92
|
|
93
93
|
# Add snapshots lane if not present
|
94
94
|
unless current_content.match?(/^\s*lane\s*:build_upload_emerge_snapshot\s*do/)
|
95
|
-
snapshot_lane = <<~
|
95
|
+
snapshot_lane = <<~RUBY.gsub(/^/, ' ')
|
96
96
|
desc 'Build and upload snapshot build to Emerge Tools'
|
97
97
|
lane :build_upload_emerge_snapshot do
|
98
98
|
emerge_snapshot(scheme: ENV["SCHEME_NAME"])
|
@@ -51,8 +51,8 @@ module EmergeCLI
|
|
51
51
|
success = false
|
52
52
|
|
53
53
|
begin
|
54
|
-
api_token = @options[:api_token] || ENV
|
55
|
-
raise 'API token is required'
|
54
|
+
api_token = @options[:api_token] || ENV.fetch('EMERGE_API_TOKEN', nil)
|
55
|
+
raise 'API token is required and cannot be blank' if api_token.nil? || api_token.strip.empty?
|
56
56
|
|
57
57
|
@network ||= EmergeCLI::Network.new(api_token:)
|
58
58
|
@git_info_provider ||= GitInfoProvider.new
|
@@ -133,8 +133,8 @@ module EmergeCLI
|
|
133
133
|
|
134
134
|
if seen_files[file_name]
|
135
135
|
Logger.warn "Duplicate file name detected: '#{file_name}'. " \
|
136
|
-
|
137
|
-
|
136
|
+
"Previous occurrence: '#{seen_files[file_name]}'. " \
|
137
|
+
'This upload will overwrite the previous one.'
|
138
138
|
end
|
139
139
|
seen_files[file_name] = image_path
|
140
140
|
end
|
data/lib/emerge_cli.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
|
-
require_relative '
|
2
|
-
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
10
|
-
|
11
|
-
require_relative '
|
12
|
-
|
13
|
-
require_relative '
|
14
|
-
|
15
|
-
require_relative '
|
16
|
-
require_relative '
|
17
|
-
require_relative '
|
18
|
-
require_relative '
|
1
|
+
require_relative 'version'
|
2
|
+
|
3
|
+
require_relative 'commands/global_options'
|
4
|
+
require_relative 'commands/upload/snapshots/snapshots'
|
5
|
+
require_relative 'commands/upload/snapshots/client_libraries/swift_snapshot_testing'
|
6
|
+
require_relative 'commands/upload/snapshots/client_libraries/paparazzi'
|
7
|
+
require_relative 'commands/upload/snapshots/client_libraries/roborazzi'
|
8
|
+
require_relative 'commands/upload/snapshots/client_libraries/default'
|
9
|
+
require_relative 'commands/integrate/fastlane'
|
10
|
+
require_relative 'commands/config/snapshots/snapshots_ios'
|
11
|
+
require_relative 'commands/config/orderfiles/orderfiles_ios'
|
12
|
+
|
13
|
+
require_relative 'reaper/ast_parser'
|
14
|
+
|
15
|
+
require_relative 'utils/git_info_provider'
|
16
|
+
require_relative 'utils/git_result'
|
17
|
+
require_relative 'utils/github'
|
18
|
+
require_relative 'utils/git'
|
19
|
+
require_relative 'utils/logger'
|
20
|
+
require_relative 'utils/network'
|
21
|
+
require_relative 'utils/profiler'
|
22
|
+
require_relative 'utils/project_detector'
|
19
23
|
|
20
24
|
require 'dry/cli'
|
25
|
+
require 'pry'
|
26
|
+
require 'pry-byebug'
|
21
27
|
|
22
28
|
module EmergeCLI
|
23
29
|
extend Dry::CLI::Registry
|
@@ -37,4 +43,4 @@ module EmergeCLI
|
|
37
43
|
end
|
38
44
|
|
39
45
|
# By default the log level is INFO, but can be overridden by the --debug flag
|
40
|
-
EmergeCLI::Logger.configure(
|
46
|
+
EmergeCLI::Logger.configure(Logger::INFO)
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'tree_sitter'
|
2
|
+
|
3
|
+
module Emerge
|
4
|
+
module Reaper
|
5
|
+
# Parses the AST of a given file using Tree Sitter and allows us to find usages or delete types.
|
6
|
+
# This does have a lot of limitations since it only looks at a single file at a time,
|
7
|
+
# but can get us most of the way there.
|
8
|
+
class AstParser
|
9
|
+
DECLARATION_NODE_TYPES = {
|
10
|
+
'swift' => %i[class_declaration protocol_declaration],
|
11
|
+
'kotlin' => %i[class_declaration protocol_declaration interface_declaration],
|
12
|
+
'java' => %i[class_declaration protocol_declaration interface_declaration]
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
IDENTIFIER_NODE_TYPES = {
|
16
|
+
'swift' => %i[simple_identifier qualified_name identifier type_identifier],
|
17
|
+
'kotlin' => %i[simple_identifier qualified_name identifier type_identifier],
|
18
|
+
'java' => %i[simple_identifier qualified_name identifier type_identifier]
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
COMMENT_AND_IMPORT_NODE_TYPES = {
|
22
|
+
'swift' => %i[comment import_declaration],
|
23
|
+
'kotlin' => %i[comment import_header],
|
24
|
+
'java' => %i[comment import_declaration]
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
attr_reader :parser, :language
|
28
|
+
|
29
|
+
def initialize(language)
|
30
|
+
@parser = TreeSitter::Parser.new
|
31
|
+
@language = language
|
32
|
+
@current_file_contents = nil
|
33
|
+
|
34
|
+
platform = case RUBY_PLATFORM
|
35
|
+
when /darwin/
|
36
|
+
'darwin'
|
37
|
+
when /linux/
|
38
|
+
'linux'
|
39
|
+
else
|
40
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
41
|
+
end
|
42
|
+
|
43
|
+
arch = case RUBY_PLATFORM
|
44
|
+
when /x86_64|amd64/
|
45
|
+
'x86_64'
|
46
|
+
when /arm64|aarch64/
|
47
|
+
'arm64'
|
48
|
+
else
|
49
|
+
raise "Unsupported architecture: #{RUBY_PLATFORM}"
|
50
|
+
end
|
51
|
+
|
52
|
+
extension = platform == 'darwin' ? 'dylib' : 'so'
|
53
|
+
parser_file = "libtree-sitter-#{language}-#{platform}-#{arch}.#{extension}"
|
54
|
+
parser_path = File.join('parsers', parser_file)
|
55
|
+
|
56
|
+
case language
|
57
|
+
when 'swift'
|
58
|
+
@parser.language = TreeSitter::Language.load('swift', parser_path)
|
59
|
+
when 'kotlin'
|
60
|
+
@parser.language = TreeSitter::Language.load('kotlin', parser_path)
|
61
|
+
when 'java'
|
62
|
+
@parser.language = TreeSitter::Language.load('java', parser_path)
|
63
|
+
else
|
64
|
+
raise "Unsupported language: #{language}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Deletes a type from the given file contents.
|
69
|
+
# Returns the modified file contents if successful, otherwise nil.
|
70
|
+
# TODO(telkins): Look into the tree-sitter query API to see if it simplifies this.
|
71
|
+
def delete_type(file_contents:, type_name:)
|
72
|
+
@current_file_contents = file_contents
|
73
|
+
tree = @parser.parse_string(nil, file_contents)
|
74
|
+
cursor = TreeSitter::TreeCursor.new(tree.root_node)
|
75
|
+
nodes_to_process = [cursor.current_node]
|
76
|
+
lines_to_remove = []
|
77
|
+
|
78
|
+
while (node = nodes_to_process.shift)
|
79
|
+
if declaration_node_types.include?(node.type)
|
80
|
+
type_identifier_node = find_type_identifier(node)
|
81
|
+
if type_identifier_node && fully_qualified_type_name(type_identifier_node) == type_name
|
82
|
+
remove_node(node, lines_to_remove)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if extension?(node)
|
87
|
+
user_type_nodes = node.select { |n| n.type == :user_type }
|
88
|
+
if user_type_nodes.length >= 1 && fully_qualified_type_name(user_type_nodes[0]) == type_name
|
89
|
+
remove_node(node, lines_to_remove)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
node.each_named { |child| nodes_to_process.push(child) }
|
94
|
+
end
|
95
|
+
|
96
|
+
lines = file_contents.split("\n")
|
97
|
+
lines_to_remove.each do |range|
|
98
|
+
(range[:start]..range[:end]).each { |i| lines[i] = nil }
|
99
|
+
|
100
|
+
# Remove extra newline after class declaration, but only if it's blank
|
101
|
+
if range[:end] + 1 < lines.length && !lines[range[:end] + 1].nil? && lines[range[:end] + 1].match?(/^\s*$/)
|
102
|
+
lines[range[:end] + 1] = nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
modified_source = lines.compact.join("\n")
|
107
|
+
new_tree = @parser.parse_string(nil, modified_source)
|
108
|
+
|
109
|
+
return nil if only_comments_and_imports?(TreeSitter::TreeCursor.new(new_tree.root_node))
|
110
|
+
modified_source
|
111
|
+
end
|
112
|
+
|
113
|
+
# Finds all usages of a given type in a file.
|
114
|
+
# TODO(telkins): Look into the tree-sitter query API to see if it simplifies this.
|
115
|
+
def find_usages(file_contents:, type_name:)
|
116
|
+
@current_file_contents = file_contents
|
117
|
+
tree = @parser.parse_string(nil, file_contents)
|
118
|
+
cursor = TreeSitter::TreeCursor.new(tree.root_node)
|
119
|
+
usages = []
|
120
|
+
nodes_to_process = [cursor.current_node]
|
121
|
+
|
122
|
+
while (node = nodes_to_process.shift)
|
123
|
+
identifier_type = identifier_node_types.include?(node.type)
|
124
|
+
declaration_type = if node == tree.root_node
|
125
|
+
false
|
126
|
+
else
|
127
|
+
declaration_node_types.include?(node.parent&.type)
|
128
|
+
end
|
129
|
+
if declaration_type && fully_qualified_type_name(node) == type_name
|
130
|
+
usages << { line: node.start_point.row, usage_type: 'declaration' }
|
131
|
+
elsif identifier_type && node_text(node) == type_name
|
132
|
+
usages << { line: node.start_point.row, usage_type: 'identifier' }
|
133
|
+
end
|
134
|
+
|
135
|
+
node.each { |child| nodes_to_process.push(child) }
|
136
|
+
end
|
137
|
+
|
138
|
+
usages
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def remove_node(node, lines_to_remove)
|
144
|
+
start_position = node.start_point.row
|
145
|
+
end_position = node.end_point.row
|
146
|
+
lines_to_remove << { start: start_position, end: end_position }
|
147
|
+
|
148
|
+
# Remove comments preceding the class declaration
|
149
|
+
predecessor = node.prev_named_sibling
|
150
|
+
return unless predecessor && predecessor.type == :comment
|
151
|
+
lines_to_remove << { start: predecessor.start_point.row, end: predecessor.end_point.row }
|
152
|
+
end
|
153
|
+
|
154
|
+
def extension?(node)
|
155
|
+
if node.type == :class_declaration
|
156
|
+
!node.find { |n| n.type == :extension }.nil?
|
157
|
+
else
|
158
|
+
false
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def only_comments_and_imports?(root)
|
163
|
+
types = comment_and_import_types
|
164
|
+
root.current_node.all? do |child|
|
165
|
+
types.include?(child.type)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Reaper expects a fully qualified type name, so we need to extract it from the AST.
|
170
|
+
# E.g. `MyModule.MyClass`
|
171
|
+
def fully_qualified_type_name(node)
|
172
|
+
class_name = node_text(node)
|
173
|
+
current_node = node
|
174
|
+
parent = find_parent_type_declaration(current_node)
|
175
|
+
|
176
|
+
while parent
|
177
|
+
type_identifier = find_type_identifier(parent)
|
178
|
+
user_type = find_user_type(parent)
|
179
|
+
|
180
|
+
if type_identifier && type_identifier != current_node
|
181
|
+
class_name = "#{node_text(type_identifier)}.#{class_name}"
|
182
|
+
current_node = type_identifier
|
183
|
+
elsif user_type && user_type != current_node
|
184
|
+
class_name = "#{node_text(user_type)}.#{class_name}"
|
185
|
+
current_node = user_type
|
186
|
+
end
|
187
|
+
|
188
|
+
parent = find_parent_type_declaration(parent)
|
189
|
+
end
|
190
|
+
|
191
|
+
class_name
|
192
|
+
end
|
193
|
+
|
194
|
+
def find_parent_type_declaration(node)
|
195
|
+
return nil unless node&.parent
|
196
|
+
|
197
|
+
current = node.parent
|
198
|
+
while current && !current.null?
|
199
|
+
return current if current.type && declaration_node_types.include?(current.type)
|
200
|
+
break unless current.parent && !current.parent.null?
|
201
|
+
current = current.parent
|
202
|
+
end
|
203
|
+
nil
|
204
|
+
end
|
205
|
+
|
206
|
+
def find_type_identifier(node)
|
207
|
+
node.find { |n| identifier_node_types.include?(n.type) }
|
208
|
+
end
|
209
|
+
|
210
|
+
def find_user_type(node)
|
211
|
+
node.find { |n| n.type == :user_type }
|
212
|
+
end
|
213
|
+
|
214
|
+
def declaration_node_types
|
215
|
+
DECLARATION_NODE_TYPES[language]
|
216
|
+
end
|
217
|
+
|
218
|
+
def identifier_node_types
|
219
|
+
IDENTIFIER_NODE_TYPES[language]
|
220
|
+
end
|
221
|
+
|
222
|
+
def comment_and_import_types
|
223
|
+
COMMENT_AND_IMPORT_NODE_TYPES[language]
|
224
|
+
end
|
225
|
+
|
226
|
+
def node_text(node)
|
227
|
+
return '' unless @current_file_contents
|
228
|
+
start_byte = node.start_byte
|
229
|
+
end_byte = node.end_byte
|
230
|
+
@current_file_contents[start_byte...end_byte]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
data/lib/utils/git.rb
CHANGED
data/lib/utils/github.rb
CHANGED
@@ -4,7 +4,7 @@ module EmergeCLI
|
|
4
4
|
GITHUB_EVENT_PUSH = 'push'.freeze
|
5
5
|
|
6
6
|
def self.event_name
|
7
|
-
ENV
|
7
|
+
ENV.fetch('GITHUB_EVENT_NAME', nil)
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.supported_github_event?
|
@@ -22,7 +22,7 @@ module EmergeCLI
|
|
22
22
|
|
23
23
|
def self.sha
|
24
24
|
if push?
|
25
|
-
ENV
|
25
|
+
ENV.fetch('GITHUB_SHA', nil)
|
26
26
|
elsif pull_request?
|
27
27
|
github_event_data.dig(:pull_request, :head, :sha)
|
28
28
|
end
|
@@ -55,7 +55,7 @@ module EmergeCLI
|
|
55
55
|
|
56
56
|
def self.github_event_data
|
57
57
|
@github_event_data ||= begin
|
58
|
-
github_event_path = ENV
|
58
|
+
github_event_path = ENV.fetch('GITHUB_EVENT_PATH', nil)
|
59
59
|
Logger.error 'GITHUB_EVENT_PATH is not set' if github_event_path.nil?
|
60
60
|
|
61
61
|
Logger.error "File #{github_event_path} doesn't exist" unless File.exist?(github_event_path)
|
data/lib/utils/logger.rb
CHANGED
data/lib/utils/network.rb
CHANGED
@@ -9,7 +9,7 @@ module EmergeCLI
|
|
9
9
|
public_constant :EMERGE_API_PROD_URL
|
10
10
|
|
11
11
|
RETRY_DELAY = 5
|
12
|
-
MAX_RETRIES =
|
12
|
+
MAX_RETRIES = 3
|
13
13
|
|
14
14
|
def initialize(api_token:, base_url: EMERGE_API_PROD_URL)
|
15
15
|
@base_url = base_url
|
@@ -43,7 +43,10 @@ module EmergeCLI
|
|
43
43
|
end
|
44
44
|
absolute_uri = uri.to_s
|
45
45
|
|
46
|
-
headers = {
|
46
|
+
headers = {
|
47
|
+
'X-API-Token' => @api_token,
|
48
|
+
'User-Agent' => "emerge-cli/#{EmergeCLI::VERSION}"
|
49
|
+
}
|
47
50
|
headers['Content-Type'] = 'application/json' if method == :post && body.is_a?(Hash)
|
48
51
|
headers.merge!(custom_headers)
|
49
52
|
|
@@ -62,20 +65,32 @@ module EmergeCLI
|
|
62
65
|
|
63
66
|
response
|
64
67
|
rescue StandardError => e
|
65
|
-
|
66
|
-
if
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
retries += 1
|
69
|
+
if retries <= MAX_RETRIES
|
70
|
+
delay = RETRY_DELAY * retries
|
71
|
+
error_message = e.message
|
72
|
+
Logger.warn "Request failed (attempt #{retries}/#{MAX_RETRIES}): #{error_message}"
|
73
|
+
Logger.warn "Retrying in #{delay} seconds..."
|
74
|
+
|
75
|
+
begin
|
76
|
+
@internet.close
|
77
|
+
rescue StandardError
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
@internet = Async::HTTP::Internet.new
|
81
|
+
|
82
|
+
sleep delay
|
70
83
|
retry
|
71
84
|
else
|
72
|
-
Logger.error "Request failed: #{absolute_uri} #{e.message}"
|
85
|
+
Logger.error "Request failed after #{MAX_RETRIES} attempts: #{absolute_uri} #{e.message}"
|
73
86
|
raise e
|
74
87
|
end
|
75
88
|
end
|
76
89
|
end
|
77
90
|
|
78
91
|
def perform_request(method, absolute_uri, headers, body)
|
92
|
+
headers ||= {}
|
93
|
+
|
79
94
|
case method
|
80
95
|
when :get
|
81
96
|
@internet.get(absolute_uri, headers:)
|
data/lib/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = '0.2.
|
1
|
+
module EmergeCLI
|
2
|
+
VERSION = '0.2.2'.freeze
|
3
3
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emerge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emerge Tools
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.21.1
|
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: 2.
|
26
|
+
version: 2.21.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: async-http
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.86.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.86.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: chunky_png
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.4.0
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: colorize
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.1.0
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.1.0
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: dry-cli
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,145 +81,75 @@ dependencies:
|
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: 0.2.1
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
84
|
+
name: pry-byebug
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - "~>"
|
102
88
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
89
|
+
version: '3.8'
|
104
90
|
type: :runtime
|
105
91
|
prerelease: false
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
107
93
|
requirements:
|
108
94
|
- - "~>"
|
109
95
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
96
|
+
version: '3.8'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
98
|
+
name: ruby_tree_sitter
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
101
|
- - "~>"
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
103
|
+
version: '1.9'
|
118
104
|
type: :runtime
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
107
|
requirements:
|
122
108
|
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
110
|
+
version: '1.9'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
112
|
+
name: tty-prompt
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
128
114
|
requirements:
|
129
115
|
- - "~>"
|
130
116
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
117
|
+
version: 0.23.1
|
132
118
|
type: :runtime
|
133
119
|
prerelease: false
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
135
121
|
requirements:
|
136
122
|
- - "~>"
|
137
123
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: minitest
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: 5.25.1
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: 5.25.1
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: minitest-reporters
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 1.7.1
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 1.7.1
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: pry
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: 0.15.0
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: 0.15.0
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: rake
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: 13.2.1
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: 13.2.1
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: rspec
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - "~>"
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: 3.13.0
|
202
|
-
type: :development
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - "~>"
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: 3.13.0
|
124
|
+
version: 0.23.1
|
209
125
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
126
|
+
name: tty-table
|
211
127
|
requirement: !ruby/object:Gem::Requirement
|
212
128
|
requirements:
|
213
129
|
- - "~>"
|
214
130
|
- !ruby/object:Gem::Version
|
215
|
-
version:
|
216
|
-
type: :
|
131
|
+
version: 0.12.0
|
132
|
+
type: :runtime
|
217
133
|
prerelease: false
|
218
134
|
version_requirements: !ruby/object:Gem::Requirement
|
219
135
|
requirements:
|
220
136
|
- - "~>"
|
221
137
|
- !ruby/object:Gem::Version
|
222
|
-
version:
|
138
|
+
version: 0.12.0
|
223
139
|
- !ruby/object:Gem::Dependency
|
224
|
-
name:
|
140
|
+
name: xcodeproj
|
225
141
|
requirement: !ruby/object:Gem::Requirement
|
226
142
|
requirements:
|
227
143
|
- - "~>"
|
228
144
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
230
|
-
type: :
|
145
|
+
version: 1.27.0
|
146
|
+
type: :runtime
|
231
147
|
prerelease: false
|
232
148
|
version_requirements: !ruby/object:Gem::Requirement
|
233
149
|
requirements:
|
234
150
|
- - "~>"
|
235
151
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
152
|
+
version: 1.27.0
|
237
153
|
description: The official CLI for Emerge Tools
|
238
154
|
email:
|
239
155
|
- support@emergetools.com
|
@@ -255,6 +171,7 @@ files:
|
|
255
171
|
- lib/commands/upload/snapshots/client_libraries/swift_snapshot_testing.rb
|
256
172
|
- lib/commands/upload/snapshots/snapshots.rb
|
257
173
|
- lib/emerge_cli.rb
|
174
|
+
- lib/reaper/ast_parser.rb
|
258
175
|
- lib/utils/git.rb
|
259
176
|
- lib/utils/git_info_provider.rb
|
260
177
|
- lib/utils/git_result.rb
|
@@ -271,6 +188,7 @@ metadata:
|
|
271
188
|
homepage_uri: https://github.com/EmergeTools/emerge-cli
|
272
189
|
source_code_uri: https://github.com/EmergeTools/emerge-cli
|
273
190
|
changelog_uri: https://github.com/EmergeTools/emerge-cli/blob/main/CHANGELOG.md
|
191
|
+
rubygems_mfa_required: 'true'
|
274
192
|
post_install_message:
|
275
193
|
rdoc_options: []
|
276
194
|
require_paths:
|