emerge 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd7bc43fdddfcd51ef2ebe7a5fe44510137974eef76b54bef580fc063adf9154
4
- data.tar.gz: 5d1dc8515182aa0eebf2db62ebb7f659099c9fc29de9ea70be874146a30d3c88
3
+ metadata.gz: 4a44399f9df18a4ce4d32984e12eaadb2fa921c34409d8e4daa0dd1b4acddd2c
4
+ data.tar.gz: 855d965c1478cbc23eee27f5f99281d1a144b7c40197bdb693fac7d93f0be72d
5
5
  SHA512:
6
- metadata.gz: '012119f0978a9a996d33e5de12a0aef3b04a996123bbd20aa8fe9cdc0cd5e7763335ee4b3b22d94852ed768de436f50562009e185dfb195ce3bd527028eb4810'
7
- data.tar.gz: dac2c3e4324c29746d75f689ebc1e4d92f2fcda30c4c30b6cadd79367f0ee4af7c0b465e0a082e6dfdfa886bace6c791bbfec3949aa18645cbde33f881d2300f
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.
@@ -18,8 +18,6 @@ module EmergeCLI
18
18
  ORDER_FILE = 'ORDER_FILE'.freeze
19
19
  ORDER_FILE_PATH = '$(PROJECT_DIR)/orderfiles/orderfile.txt'.freeze
20
20
 
21
- def initialize; end
22
-
23
21
  def call(**options)
24
22
  @options = options
25
23
  before(options)
@@ -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
- previews_exact.each do |preview|
209
- excluded.push({
210
- 'type' => 'exact',
211
- 'value' => preview
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 = <<~'RUBY'.gsub(/^/, ' ')
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 = <<~'RUBY'.gsub(/^/, ' ')
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"])
@@ -48,10 +48,11 @@ module EmergeCLI
48
48
 
49
49
  start_time = Time.now
50
50
  run_id = nil
51
+ success = false
51
52
 
52
53
  begin
53
- api_token = @options[:api_token] || ENV['EMERGE_API_TOKEN']
54
- raise 'API token is required' unless api_token
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?
55
56
 
56
57
  @network ||= EmergeCLI::Network.new(api_token:)
57
58
  @git_info_provider ||= GitInfoProvider.new
@@ -76,12 +77,16 @@ module EmergeCLI
76
77
  Logger.info "Time taken: #{(Time.now - start_time).round(2)} seconds"
77
78
  @profiler.report
78
79
  Logger.info "✅ View your snapshots at https://emergetools.com/snapshot/#{run_id}"
80
+ success = true
79
81
  rescue StandardError => e
80
82
  Logger.error "CLI Error: #{e.message}"
81
83
  Sync { report_error(run_id, e.message, 'crash') } if run_id
84
+ raise e # Re-raise the error to dry-cli
82
85
  ensure
83
86
  @network&.close
84
87
  end
88
+
89
+ success
85
90
  end
86
91
 
87
92
  private
@@ -116,6 +121,7 @@ module EmergeCLI
116
121
 
117
122
  def find_image_files(client)
118
123
  found_images = client.image_files
124
+ raise 'No images found. Please check your image paths or project configuration.' if found_images.empty?
119
125
  Logger.info "Found #{found_images.size} images"
120
126
  found_images
121
127
  end
@@ -127,8 +133,8 @@ module EmergeCLI
127
133
 
128
134
  if seen_files[file_name]
129
135
  Logger.warn "Duplicate file name detected: '#{file_name}'. " \
130
- "Previous occurrence: '#{seen_files[file_name]}'. " \
131
- 'This upload will overwrite the previous one.'
136
+ "Previous occurrence: '#{seen_files[file_name]}'. " \
137
+ 'This upload will overwrite the previous one.'
132
138
  end
133
139
  seen_files[file_name] = image_path
134
140
  end
data/lib/emerge_cli.rb CHANGED
@@ -1,23 +1,29 @@
1
- require_relative './commands/global_options'
2
- require_relative './commands/upload/snapshots/snapshots'
3
- require_relative './commands/upload/snapshots/client_libraries/swift_snapshot_testing'
4
- require_relative './commands/upload/snapshots/client_libraries/paparazzi'
5
- require_relative './commands/upload/snapshots/client_libraries/roborazzi'
6
- require_relative './commands/upload/snapshots/client_libraries/default'
7
- require_relative './commands/integrate/fastlane'
8
- require_relative './commands/config/snapshots/snapshots_ios'
9
- require_relative './commands/config/orderfiles/orderfiles_ios'
10
-
11
- require_relative './utils/git_info_provider'
12
- require_relative './utils/git_result'
13
- require_relative './utils/github'
14
- require_relative './utils/git'
15
- require_relative './utils/logger'
16
- require_relative './utils/network'
17
- require_relative './utils/profiler'
18
- require_relative './utils/project_detector'
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(::Logger::INFO)
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
@@ -81,7 +81,7 @@ module EmergeCLI
81
81
  .split("\n")
82
82
  .map(&:strip)
83
83
  .find { |line| line.start_with?('HEAD branch: ') }
84
- &.split(' ')
84
+ &.split
85
85
  &.last
86
86
  end
87
87
 
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['GITHUB_EVENT_NAME']
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['GITHUB_SHA']
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['GITHUB_EVENT_PATH']
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
@@ -1,5 +1,5 @@
1
1
  require 'logger'
2
- require 'colorize'
2
+ require 'colored2'
3
3
 
4
4
  module EmergeCLI
5
5
  class Logger
@@ -43,7 +43,7 @@ module EmergeCLI
43
43
  when 'ERROR'
44
44
  msg.to_s.red
45
45
  when 'DEBUG'
46
- msg.to_s.light_blue
46
+ msg.to_s.blue
47
47
  else
48
48
  msg.to_s
49
49
  end
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 = 1
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 = { 'X-API-Token' => @api_token }
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
- # Workaround for an issue where the request is not fully written, haven't determined the root cause yet
66
- if e.message.include?('Wrote 0 bytes') && retries < MAX_RETRIES
67
- retries += 1
68
- Logger.warn "Request failed due to incomplete write. Retrying in #{RETRY_DELAY} seconds..."
69
- sleep RETRY_DELAY
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 EmergeCli
2
- VERSION = '0.2.0'.freeze
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.0
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-20 00:00:00.000000000 Z
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.20.0
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.20.0
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.83.1
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.83.1
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: tty-prompt
84
+ name: pry-byebug
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: 0.23.1
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: 0.23.1
96
+ version: '3.8'
111
97
  - !ruby/object:Gem::Dependency
112
- name: tty-table
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: 0.12.0
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: 0.12.0
110
+ version: '1.9'
125
111
  - !ruby/object:Gem::Dependency
126
- name: xcodeproj
112
+ name: tty-prompt
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
115
  - - "~>"
130
116
  - !ruby/object:Gem::Version
131
- version: 1.27.0
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: 1.27.0
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: rubocop
126
+ name: tty-table
211
127
  requirement: !ruby/object:Gem::Requirement
212
128
  requirements:
213
129
  - - "~>"
214
130
  - !ruby/object:Gem::Version
215
- version: 1.68.0
216
- type: :development
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: 1.68.0
138
+ version: 0.12.0
223
139
  - !ruby/object:Gem::Dependency
224
- name: simplecov
140
+ name: xcodeproj
225
141
  requirement: !ruby/object:Gem::Requirement
226
142
  requirements:
227
143
  - - "~>"
228
144
  - !ruby/object:Gem::Version
229
- version: 0.22.0
230
- type: :development
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: 0.22.0
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: