tng 0.3.0 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +20 -43
- data/bin/tng +264 -558
- data/binaries/go-ui-darwin-amd64 +0 -0
- data/binaries/go-ui-darwin-arm64 +0 -0
- data/binaries/go-ui-linux-amd64 +0 -0
- data/binaries/go-ui-linux-arm64 +0 -0
- data/binaries/tng-darwin-arm64.bundle +0 -0
- data/binaries/tng-linux-arm64.so +0 -0
- data/binaries/tng-linux-x86_64.so +0 -0
- data/lib/tng/api/http_client.rb +19 -0
- data/lib/tng/services/test_generator.rb +114 -81
- data/lib/tng/services/testng.rb +2 -8
- data/lib/tng/ui/go_ui_session.rb +406 -0
- data/lib/tng/utils.rb +3 -30
- data/lib/tng/version.rb +1 -1
- data/lib/tng.rb +24 -11
- data/tng.gemspec +4 -9
- metadata +55 -126
- data/binaries/tng.bundle +0 -0
- data/binaries/tng.so +0 -0
- data/lib/tng/ui/about_display.rb +0 -66
- data/lib/tng/ui/authentication_warning_display.rb +0 -122
- data/lib/tng/ui/configuration_display.rb +0 -52
- data/lib/tng/ui/controller_test_flow_display.rb +0 -79
- data/lib/tng/ui/display_banner.rb +0 -44
- data/lib/tng/ui/goodbye_display.rb +0 -41
- data/lib/tng/ui/model_test_flow_display.rb +0 -80
- data/lib/tng/ui/other_test_flow_display.rb +0 -78
- data/lib/tng/ui/service_test_flow_display.rb +0 -78
- data/lib/tng/ui/show_help.rb +0 -78
- data/lib/tng/ui/system_status_display.rb +0 -128
- data/lib/tng/ui/user_stats_display.rb +0 -160
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "tempfile"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
|
|
7
|
+
module Tng
|
|
8
|
+
module UI
|
|
9
|
+
# Ruby wrapper for calling go-ui binary
|
|
10
|
+
class GoUISession
|
|
11
|
+
def initialize
|
|
12
|
+
@binary_path = find_go_ui_binary
|
|
13
|
+
@running = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def start
|
|
17
|
+
@running = true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop
|
|
21
|
+
@running = false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def running?
|
|
25
|
+
@running
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Show main menu and return selected choice
|
|
29
|
+
# Returns: "tests", "stats", "about", "exit"
|
|
30
|
+
def show_menu
|
|
31
|
+
output_file = Tempfile.new(["go_ui_menu", ".json"])
|
|
32
|
+
output_path = output_file.path
|
|
33
|
+
output_file.close
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
system(@binary_path, "menu", "--output", output_path)
|
|
37
|
+
|
|
38
|
+
return "exit" unless File.exist?(output_path) && File.size(output_path) > 0
|
|
39
|
+
|
|
40
|
+
choice = File.read(output_path).strip
|
|
41
|
+
choice.empty? ? "exit" : choice
|
|
42
|
+
rescue StandardError
|
|
43
|
+
"exit"
|
|
44
|
+
ensure
|
|
45
|
+
File.unlink(output_path) if File.exist?(output_path)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Show test type selection menu
|
|
50
|
+
# Returns: "controller", "model", "service", "other", "back"
|
|
51
|
+
def show_test_type_menu
|
|
52
|
+
output_file = Tempfile.new(["go_ui_test_type", ".json"])
|
|
53
|
+
output_path = output_file.path
|
|
54
|
+
output_file.close
|
|
55
|
+
|
|
56
|
+
begin
|
|
57
|
+
system(@binary_path, "rails-test-menu", "--output", output_path)
|
|
58
|
+
|
|
59
|
+
return "back" unless File.exist?(output_path) && File.size(output_path) > 0
|
|
60
|
+
|
|
61
|
+
choice = File.read(output_path).strip
|
|
62
|
+
choice.empty? ? "back" : choice
|
|
63
|
+
rescue StandardError
|
|
64
|
+
"back"
|
|
65
|
+
ensure
|
|
66
|
+
File.unlink(output_path) if File.exist?(output_path)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Show searchable list view for any component
|
|
71
|
+
# @param title [String] List title (e.g., "Select Controller")
|
|
72
|
+
# @param items [Array<Hash>] List of items with :name and :path keys
|
|
73
|
+
# @return [String] Selected item name or "back"
|
|
74
|
+
def show_list_view(title, items)
|
|
75
|
+
data_json = JSON.generate({ title: title, items: items })
|
|
76
|
+
|
|
77
|
+
output_file = Tempfile.new(["go_ui_list", ".txt"])
|
|
78
|
+
output_path = output_file.path
|
|
79
|
+
output_file.close
|
|
80
|
+
|
|
81
|
+
begin
|
|
82
|
+
system(@binary_path, "list-view", "--data", data_json, "--output", output_path)
|
|
83
|
+
|
|
84
|
+
selected = File.read(output_path).strip
|
|
85
|
+
selected.empty? ? "back" : selected
|
|
86
|
+
ensure
|
|
87
|
+
File.unlink(output_path) if File.exist?(output_path)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Show spinner while executing block
|
|
92
|
+
# @param message [String] Spinner message
|
|
93
|
+
# @yield Block that returns Hash with :success and :message keys
|
|
94
|
+
# @return [Hash] Result from block
|
|
95
|
+
def show_spinner(message, &block)
|
|
96
|
+
control_file = Tempfile.new(["go_ui_spinner", ".json"])
|
|
97
|
+
control_path = control_file.path
|
|
98
|
+
control_file.close
|
|
99
|
+
|
|
100
|
+
# Start spinner in background
|
|
101
|
+
pid = spawn(@binary_path, "spinner", "--message", message, "--control", control_path)
|
|
102
|
+
|
|
103
|
+
begin
|
|
104
|
+
result = yield
|
|
105
|
+
|
|
106
|
+
# Write completion status
|
|
107
|
+
status = {
|
|
108
|
+
status: result&.dig(:success) ? "success" : "error",
|
|
109
|
+
message: result&.dig(:message) || "Done!"
|
|
110
|
+
}
|
|
111
|
+
File.write(control_path, JSON.generate(status))
|
|
112
|
+
|
|
113
|
+
Process.wait(pid)
|
|
114
|
+
result
|
|
115
|
+
rescue StandardError => e
|
|
116
|
+
status = { status: "error", message: e.message }
|
|
117
|
+
File.write(control_path, JSON.generate(status))
|
|
118
|
+
Process.wait(pid)
|
|
119
|
+
raise
|
|
120
|
+
ensure
|
|
121
|
+
File.unlink(control_path) if File.exist?(control_path)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Show progress bar with steps
|
|
126
|
+
# @param title [String] Progress title
|
|
127
|
+
# @yield [ProgressUpdater] Block receives updater and returns Hash with :message and :result
|
|
128
|
+
# @return [Hash] Result from block
|
|
129
|
+
def show_progress(title, &block)
|
|
130
|
+
control_file = Tempfile.new(["go_ui_progress", ".json"])
|
|
131
|
+
control_path = control_file.path
|
|
132
|
+
control_file.close
|
|
133
|
+
|
|
134
|
+
# Start progress in background (inherit TTY)
|
|
135
|
+
pid = spawn(@binary_path, "progress", "--title", title, "--control", control_path)
|
|
136
|
+
|
|
137
|
+
begin
|
|
138
|
+
updater = ProgressUpdater.new(control_path)
|
|
139
|
+
result = yield(updater)
|
|
140
|
+
|
|
141
|
+
# Write completion status
|
|
142
|
+
if result&.dig(:result, :error)
|
|
143
|
+
# Error already written by updater.error
|
|
144
|
+
else
|
|
145
|
+
completion = { type: "complete", message: result&.dig(:message) || "Done!" }
|
|
146
|
+
File.write(control_path, JSON.generate(completion))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
Process.wait(pid)
|
|
150
|
+
result
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
error_data = { type: "error", message: "Error: #{e.message}" }
|
|
153
|
+
File.write(control_path, JSON.generate(error_data))
|
|
154
|
+
Process.wait(pid)
|
|
155
|
+
raise
|
|
156
|
+
ensure
|
|
157
|
+
File.unlink(control_path) if File.exist?(control_path)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Show 'no items found' message
|
|
162
|
+
# @param item_type [String] Type of items (e.g., "controllers", "models")
|
|
163
|
+
def show_no_items(item_type)
|
|
164
|
+
system(@binary_path, "no-items", "--type", item_type)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Show user statistics
|
|
168
|
+
# @param stats_data [Hash] Statistics data
|
|
169
|
+
def show_stats(stats_data)
|
|
170
|
+
stats_json = stats_data ? JSON.generate(stats_data) : "{}"
|
|
171
|
+
system(@binary_path, "stats", "--data", stats_json)
|
|
172
|
+
rescue StandardError => e
|
|
173
|
+
puts "Stats error: #{e.message}"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Show about screen
|
|
177
|
+
def show_about
|
|
178
|
+
system(@binary_path, "about")
|
|
179
|
+
rescue StandardError => e
|
|
180
|
+
puts "About error: #{e.message}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Show configuration error
|
|
184
|
+
# @param missing [Array] List of missing configuration items
|
|
185
|
+
def show_config_error(missing)
|
|
186
|
+
data_json = JSON.generate({ missing: missing })
|
|
187
|
+
system(@binary_path, "config-error", "--data", data_json)
|
|
188
|
+
rescue StandardError => e
|
|
189
|
+
puts "Config error: #{e.message}"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Show post-generation menu
|
|
193
|
+
# @param file_path [String] Generated test file path
|
|
194
|
+
# @param run_command [String] Command to run tests
|
|
195
|
+
# @return [String] Selected choice ("run_tests", "copy_command", "back")
|
|
196
|
+
def show_post_generation_menu(file_path, run_command)
|
|
197
|
+
data_json = JSON.generate({ file_path: file_path, run_command: run_command })
|
|
198
|
+
|
|
199
|
+
output_file = Tempfile.new(["go_ui_post_gen", ".txt"])
|
|
200
|
+
output_path = output_file.path
|
|
201
|
+
output_file.close
|
|
202
|
+
|
|
203
|
+
begin
|
|
204
|
+
system(@binary_path, "post-generation-menu", "--data", data_json, "--output", output_path)
|
|
205
|
+
|
|
206
|
+
choice = File.read(output_path).strip
|
|
207
|
+
choice.empty? ? "back" : choice
|
|
208
|
+
ensure
|
|
209
|
+
File.unlink(output_path) if File.exist?(output_path)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Show clipboard success message
|
|
214
|
+
# @param command [String] Command that was copied
|
|
215
|
+
def show_clipboard_success(command)
|
|
216
|
+
system(@binary_path, "clipboard-success", "--command", command)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Show test results
|
|
220
|
+
# @param title [String] Results title
|
|
221
|
+
# @param passed [Integer] Number of passed tests
|
|
222
|
+
# @param failed [Integer] Number of failed tests
|
|
223
|
+
# @param errors [Integer] Number of errors
|
|
224
|
+
# @param total [Integer] Total number of tests
|
|
225
|
+
# @param results [Array] Optional list of individual test results
|
|
226
|
+
def show_test_results(title, passed, failed, errors, total, results = [])
|
|
227
|
+
data = {
|
|
228
|
+
title: title,
|
|
229
|
+
passed: passed,
|
|
230
|
+
failed: failed,
|
|
231
|
+
errors: errors,
|
|
232
|
+
total: total,
|
|
233
|
+
results: results
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
data_json = JSON.generate(data)
|
|
237
|
+
system(@binary_path, "test-results", "--data", data_json)
|
|
238
|
+
rescue StandardError => e
|
|
239
|
+
puts "Test results error: #{e.message}"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Show authentication error
|
|
243
|
+
# @param message [String] Error message to display
|
|
244
|
+
def show_auth_error(message = "Authentication failed")
|
|
245
|
+
system(@binary_path, "auth-error", "--message", message)
|
|
246
|
+
rescue StandardError => e
|
|
247
|
+
puts "Auth error: #{e.message}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Show welcome banner
|
|
251
|
+
# @param version [String] Version to display
|
|
252
|
+
def show_banner(version)
|
|
253
|
+
system(@binary_path, "banner", "--version", version)
|
|
254
|
+
rescue StandardError => e
|
|
255
|
+
puts "Banner error: #{e.message}"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Show goodbye message
|
|
259
|
+
def show_goodbye
|
|
260
|
+
system(@binary_path, "goodbye")
|
|
261
|
+
rescue StandardError => e
|
|
262
|
+
puts "Goodbye error: #{e.message}"
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Show authentication warning
|
|
266
|
+
# @param missing_items [String] Description of missing items
|
|
267
|
+
# @return [String] "continue" or "cancel"
|
|
268
|
+
def show_auth_warning(missing_items = "")
|
|
269
|
+
output_file = Tempfile.new(["go_ui_auth", ".txt"])
|
|
270
|
+
output_path = output_file.path
|
|
271
|
+
output_file.close
|
|
272
|
+
|
|
273
|
+
data = { missing_items: missing_items }
|
|
274
|
+
data_json = JSON.generate(data)
|
|
275
|
+
|
|
276
|
+
pid = spawn(@binary_path, "auth-warning", "--data", data_json, out: output_path)
|
|
277
|
+
Process.wait(pid)
|
|
278
|
+
|
|
279
|
+
result = File.read(output_path).strip
|
|
280
|
+
result.empty? ? "cancel" : result
|
|
281
|
+
rescue StandardError => e
|
|
282
|
+
puts "Auth warning error: #{e.message}"
|
|
283
|
+
"cancel"
|
|
284
|
+
ensure
|
|
285
|
+
output_file&.unlink
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Show missing configuration
|
|
289
|
+
# @param missing_items [Array<String>] List of missing config items
|
|
290
|
+
def show_config_missing(missing_items)
|
|
291
|
+
data = { missing_items: Array(missing_items) }
|
|
292
|
+
data_json = JSON.generate(data)
|
|
293
|
+
system(@binary_path, "config-missing", "--data", data_json)
|
|
294
|
+
rescue StandardError => e
|
|
295
|
+
puts "Config missing error: #{e.message}"
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Show post-install message
|
|
299
|
+
# @param version [String] Version to display
|
|
300
|
+
def show_post_install(version)
|
|
301
|
+
system(@binary_path, "post-install", "--version", version)
|
|
302
|
+
rescue StandardError => e
|
|
303
|
+
puts "Post install error: #{e.message}"
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Show help
|
|
307
|
+
# @param version [String] Version to display
|
|
308
|
+
def show_help(version)
|
|
309
|
+
system(@binary_path, "help-box", "--version", version)
|
|
310
|
+
rescue StandardError => e
|
|
311
|
+
puts "Help error: #{e.message}"
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Show system status
|
|
315
|
+
# @param status [Hash] Status data from testng
|
|
316
|
+
def show_system_status(status)
|
|
317
|
+
data = {
|
|
318
|
+
status: status[:status].to_s,
|
|
319
|
+
message: status[:message],
|
|
320
|
+
local_version: status[:gem_version],
|
|
321
|
+
current_version: status[:current_version],
|
|
322
|
+
user_base_url: status[:user_base_url],
|
|
323
|
+
server_base_url: status[:server_base_url]
|
|
324
|
+
}
|
|
325
|
+
data_json = JSON.generate(data)
|
|
326
|
+
system(@binary_path, "system-status", "--data", data_json)
|
|
327
|
+
rescue StandardError => e
|
|
328
|
+
puts "System status error: #{e.message}"
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
private
|
|
332
|
+
|
|
333
|
+
def find_go_ui_binary
|
|
334
|
+
# Detect platform
|
|
335
|
+
platform = RUBY_PLATFORM
|
|
336
|
+
arch = RbConfig::CONFIG["host_cpu"]
|
|
337
|
+
|
|
338
|
+
# Normalize architecture
|
|
339
|
+
arch = case arch
|
|
340
|
+
when /x86_64|amd64/i then "amd64"
|
|
341
|
+
when /arm64|aarch64/i then "arm64"
|
|
342
|
+
else arch
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Determine binary name
|
|
346
|
+
binary_name = if platform.include?("darwin")
|
|
347
|
+
"go-ui-darwin-#{arch}"
|
|
348
|
+
elsif platform.include?("linux")
|
|
349
|
+
"go-ui-linux-#{arch}"
|
|
350
|
+
else
|
|
351
|
+
raise "Unsupported platform: #{platform}"
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Search paths
|
|
355
|
+
binary_paths = [
|
|
356
|
+
File.expand_path("../../../binaries/#{binary_name}", __dir__),
|
|
357
|
+
File.expand_path("../../../../binaries/#{binary_name}", __FILE__),
|
|
358
|
+
File.expand_path("binaries/#{binary_name}", Dir.pwd)
|
|
359
|
+
]
|
|
360
|
+
|
|
361
|
+
binary_paths.each do |path|
|
|
362
|
+
return path if File.exist?(path) && File.executable?(path)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
raise "go-ui binary not found. Searched: #{binary_paths.join(", ")}"
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Helper class for updating progress bar from within a block
|
|
370
|
+
class ProgressUpdater
|
|
371
|
+
def initialize(control_file)
|
|
372
|
+
@control_file = control_file
|
|
373
|
+
@step = 0
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# Update progress with a new step
|
|
377
|
+
# @param message [String] Progress message
|
|
378
|
+
# @param percent [Integer, nil] Optional percentage (0-100)
|
|
379
|
+
# @param step_increment [Boolean] Whether to increment step counter (default: true)
|
|
380
|
+
# @param explicit_step [Integer, nil] Optional explicit step index
|
|
381
|
+
def update(message, percent = nil, step_increment: true, explicit_step: nil)
|
|
382
|
+
step_idx = if explicit_step
|
|
383
|
+
explicit_step
|
|
384
|
+
else
|
|
385
|
+
step_increment ? @step : (@step > 0 ? @step - 1 : 0)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
data = { type: "step", step: step_idx, message: message }
|
|
389
|
+
data[:percent] = percent if percent
|
|
390
|
+
|
|
391
|
+
File.write(@control_file, JSON.generate(data))
|
|
392
|
+
@step += 1 if step_increment && explicit_step.nil?
|
|
393
|
+
sleep(0.1) # Give UI time to update
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Report an error
|
|
397
|
+
# @param message [String] Error message
|
|
398
|
+
def error(message)
|
|
399
|
+
data = { type: "error", message: message }
|
|
400
|
+
File.write(@control_file, JSON.generate(data))
|
|
401
|
+
sleep(0.1)
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
data/lib/tng/utils.rb
CHANGED
|
@@ -20,26 +20,6 @@ module Tng
|
|
|
20
20
|
end.join("\n")
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def copy_to_clipboard(text)
|
|
24
|
-
# Try to copy to clipboard
|
|
25
|
-
if system("which pbcopy > /dev/null 2>&1")
|
|
26
|
-
system("echo '#{text}' | pbcopy")
|
|
27
|
-
success_msg = @pastel.green("✅ Command copied to clipboard!")
|
|
28
|
-
elsif system("which xclip > /dev/null 2>&1")
|
|
29
|
-
system("echo '#{text}' | xclip -selection clipboard")
|
|
30
|
-
success_msg = @pastel.green("✅ Command copied to clipboard!")
|
|
31
|
-
else
|
|
32
|
-
success_msg = @pastel.yellow("📋 Copy this command:")
|
|
33
|
-
puts center_text(success_msg)
|
|
34
|
-
puts center_text(@pastel.bright_white(text))
|
|
35
|
-
@prompt.keypress(center_text(@pastel.dim("Press any key to continue...")))
|
|
36
|
-
return
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
puts center_text(success_msg)
|
|
40
|
-
@prompt.keypress(center_text(@pastel.dim("Press any key to continue...")))
|
|
41
|
-
end
|
|
42
|
-
|
|
43
23
|
def load_rails_environment
|
|
44
24
|
# Use bundler environment to avoid gem conflicts
|
|
45
25
|
require "bundler/setup"
|
|
@@ -101,22 +81,17 @@ module Tng
|
|
|
101
81
|
parsed_response = JSON.parse(test_content)
|
|
102
82
|
|
|
103
83
|
if parsed_response["error"]
|
|
104
|
-
|
|
105
|
-
return
|
|
84
|
+
return { error: :generation_failed, message: parsed_response["error"] }
|
|
106
85
|
end
|
|
107
86
|
# Validate required fields
|
|
108
87
|
unless parsed_response["file_content"]
|
|
109
|
-
|
|
110
|
-
puts "📋 Response keys: #{parsed_response.keys.inspect}"
|
|
111
|
-
return
|
|
88
|
+
return { error: :invalid_response, message: "API response missing file_content" }
|
|
112
89
|
end
|
|
113
90
|
|
|
114
91
|
# Handle both possible field names for file path
|
|
115
92
|
file_path = parsed_response["test_file_path"] || parsed_response["file_path"] || parsed_response["file_name"] || parsed_response["file"]
|
|
116
93
|
unless file_path
|
|
117
|
-
|
|
118
|
-
puts "📋 Response keys: #{parsed_response.keys.inspect}"
|
|
119
|
-
return
|
|
94
|
+
return { error: :invalid_response, message: "API response missing file path" }
|
|
120
95
|
end
|
|
121
96
|
|
|
122
97
|
begin
|
|
@@ -126,9 +101,7 @@ module Tng
|
|
|
126
101
|
FileUtils.mkdir_p(File.dirname(file_path))
|
|
127
102
|
File.write(file_path, parsed_response["file_content"])
|
|
128
103
|
end
|
|
129
|
-
puts "✅ Test generated successfully!"
|
|
130
104
|
absolute_path = File.expand_path(file_path)
|
|
131
|
-
puts "Please review the generated tests at \e]8;;file://#{absolute_path}\e\\#{file_path}\e]8;;\e\\"
|
|
132
105
|
|
|
133
106
|
# Count tests in the generated file
|
|
134
107
|
test_count = count_tests_in_file(file_path)
|
data/lib/tng/version.rb
CHANGED
data/lib/tng.rb
CHANGED
|
@@ -7,25 +7,38 @@ require_relative "tng/utils"
|
|
|
7
7
|
require_relative "tng/api/http_client"
|
|
8
8
|
require_relative "tng/ui/theme"
|
|
9
9
|
require_relative "tng/ui/post_install_box"
|
|
10
|
-
require_relative "tng/ui/
|
|
10
|
+
require_relative "tng/ui/go_ui_session"
|
|
11
11
|
require_relative "tng/services/test_generator"
|
|
12
12
|
|
|
13
13
|
require_relative "tng/railtie" if defined?(Rails)
|
|
14
14
|
|
|
15
15
|
begin
|
|
16
|
+
require "rbconfig"
|
|
17
|
+
|
|
16
18
|
platform = RUBY_PLATFORM
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
arch = RbConfig::CONFIG["host_cpu"]
|
|
20
|
+
|
|
21
|
+
# Normalize architecture names
|
|
22
|
+
arch = case arch
|
|
23
|
+
when /x86_64|amd64/i then "x86_64"
|
|
24
|
+
when /arm64|aarch64/i then "arm64"
|
|
25
|
+
else arch
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Determine OS and extension
|
|
29
|
+
os = platform.include?("darwin") ? "darwin" : "linux"
|
|
30
|
+
ext = platform.include?("darwin") ? "bundle" : "so"
|
|
24
31
|
|
|
32
|
+
# Try loading in order of preference
|
|
25
33
|
binary_paths = [
|
|
26
|
-
|
|
27
|
-
File.expand_path("
|
|
28
|
-
File.expand_path("binaries
|
|
34
|
+
# Development: simple name (rake dev output)
|
|
35
|
+
File.expand_path("tng/tng.#{ext}", __dir__),
|
|
36
|
+
File.expand_path("../binaries/tng.#{ext}", __dir__),
|
|
37
|
+
# Production: arch-specific names
|
|
38
|
+
File.expand_path("../binaries/tng-#{os}-#{arch}.#{ext}", __dir__),
|
|
39
|
+
# Fallback: current dir
|
|
40
|
+
File.expand_path("binaries/tng.#{ext}", Dir.pwd),
|
|
41
|
+
File.expand_path("binaries/tng-#{os}-#{arch}.#{ext}", Dir.pwd)
|
|
29
42
|
]
|
|
30
43
|
|
|
31
44
|
loaded = false
|
data/tng.gemspec
CHANGED
|
@@ -12,13 +12,13 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.description = "TNG (Test Next Generation) is a Rails gem that automatically generates comprehensive test files by analyzing your Ruby code using static analysis and AI. It supports models, controllers, and services with intelligent test case generation."
|
|
13
13
|
spec.homepage = "https://tng.sh/"
|
|
14
14
|
spec.required_ruby_version = ">= 3.1.0"
|
|
15
|
-
spec.required_rubygems_version = ">= 3.
|
|
15
|
+
spec.required_rubygems_version = ">= 3.0"
|
|
16
16
|
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
-
spec.metadata["source_code_uri"] = "https://github.com/tng-sh/tng-rails"
|
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/tng-sh/tng-rails-public"
|
|
20
20
|
spec.license = "Nonstandard"
|
|
21
|
-
spec.metadata["license_uri"] = "https://github.com/tng-sh/tng-rails/blob/
|
|
21
|
+
spec.metadata["license_uri"] = "https://github.com/tng-sh/tng-rails-public/blob/main/LICENSE.md"
|
|
22
22
|
|
|
23
23
|
# Package pre-compiled binaries and exclude the Rust source code.
|
|
24
24
|
spec.files = Dir.glob("lib/**/*.rb") +
|
|
@@ -31,20 +31,15 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
spec.require_paths = ["lib"]
|
|
32
32
|
spec.extensions = []
|
|
33
33
|
|
|
34
|
+
spec.add_dependency "activesupport", ">= 6.0", "< 9.0"
|
|
34
35
|
spec.add_dependency "httpx", "~> 1.5"
|
|
35
36
|
spec.add_dependency "openssl", "~> 3.3"
|
|
36
37
|
spec.add_dependency "pastel", "~> 0.8.0"
|
|
37
38
|
spec.add_dependency "prism", "~> 1.4.0"
|
|
38
39
|
spec.add_dependency "rb_sys", "~> 0.9.91"
|
|
39
40
|
spec.add_dependency "tty-box", "~> 0.7"
|
|
40
|
-
spec.add_dependency "tty-file", "~> 0.10"
|
|
41
41
|
spec.add_dependency "tty-option", "~> 0.3"
|
|
42
|
-
spec.add_dependency "tty-progressbar", "~> 0.18.3"
|
|
43
|
-
spec.add_dependency "tty-prompt", "~> 0.23"
|
|
44
|
-
spec.add_dependency "tty-reader", "~> 0.9"
|
|
45
42
|
spec.add_dependency "tty-screen", "~> 0.8"
|
|
46
|
-
spec.add_dependency "tty-spinner", "~> 0.9.3"
|
|
47
|
-
spec.add_dependency "tty-table", "~> 0.12"
|
|
48
43
|
|
|
49
44
|
spec.post_install_message = begin
|
|
50
45
|
require_relative "lib/tng/ui/post_install_box"
|