Skip to content

Commit 9c7a92b

Browse files
authored
Add command to configure snapshots (#4)
1 parent ddb179e commit 9c7a92b

File tree

4 files changed

+312
-0
lines changed

4 files changed

+312
-0
lines changed

emerge_cli.gemspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Gem::Specification.new do |spec|
3434
spec.add_dependency 'colorize', '~> 1.1.0'
3535
spec.add_dependency 'dry-cli', '~> 1.2.0'
3636
spec.add_dependency 'open3', '~> 0.2.1'
37+
spec.add_dependency 'tty-prompt', '~> 0.23.1'
38+
spec.add_dependency 'tty-table', '~> 0.12.0'
3739

3840
spec.add_development_dependency 'minitest', '~> 5.25.1'
3941
spec.add_development_dependency 'minitest-reporters', '~> 1.7.1'
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
require 'dry/cli'
2+
require 'json'
3+
require 'uri'
4+
require 'chunky_png'
5+
require 'async'
6+
require 'async/barrier'
7+
require 'async/semaphore'
8+
require 'async/http/internet/instance'
9+
require 'yaml'
10+
11+
require 'tty-prompt'
12+
require 'tty-table'
13+
14+
module EmergeCLI
15+
module Commands
16+
module Config
17+
class SnapshotsIOS < EmergeCLI::Commands::GlobalOptions
18+
desc 'Configure snapshot testing for iOS'
19+
20+
# Optional options
21+
option :interactive, type: :boolean, required: false,
22+
desc: 'Run interactively'
23+
option :clear, type: :boolean, required: false, desc: 'Clear existing configuration'
24+
option :os_version, type: :string, required: true, desc: 'OS version'
25+
option :launch_arguments, type: :array, required: false, desc: 'Launch arguments to set'
26+
option :env_variables, type: :array, required: false, desc: 'Environment variables to set'
27+
option :exact_match_excluded_previews, type: :array, required: false, desc: 'Exact match excluded previews'
28+
option :regex_excluded_previews, type: :array, required: false, desc: 'Regex excluded previews'
29+
30+
# Constants
31+
EXCLUDED_PREVIEW_PROMPT = 'Do you want to exclude any previews by exact match?'.freeze
32+
EXCLUDED_PREVIEW_FINISH_PROMPT = 'Enter the previews you want to exclude (leave blank to finish)'.freeze
33+
EXCLUDED_REGEX_PREVIEW_PROMPT = 'Do you want to exclude any previews by regex?'.freeze
34+
EXCLUDED_REGEX_PREVIEW_FINISH_PROMPT = 'Enter the previews you want to exclude (leave blank to finish)'.freeze
35+
ARGUMENTS_PROMPT = 'Do you want to set any arguments?'.freeze
36+
ARGUMENTS_FINISH_PROMPT = 'Enter the argument you want to set (leave blank to finish)'.freeze
37+
ENV_VARIABLES_PROMPT = 'Do you want to set any environment variables?'.freeze
38+
ENV_VARIABLES_FINISH_PROMPT = "Enter the environment variable you want to set (leave blank to finish) with \
39+
format KEY=VALUE".freeze
40+
AVAILABLE_OS_VERSIONS = ['17.2', '17.5', '18.0'].freeze
41+
42+
def initialize; end
43+
44+
def call(**options)
45+
@options = options
46+
before(options)
47+
48+
Sync do
49+
validate_options
50+
51+
run_interactive_mode if @options[:interactive]
52+
53+
run_non_interactive_mode if !@options[:interactive]
54+
55+
Logger.warn 'Remember to copy `emerge_config.yml` to your project XCArchive before uploading it!'
56+
end
57+
end
58+
59+
private
60+
61+
def validate_options
62+
if @options[:interactive] && (!@options[:os_version].nil? || !@options[:launch_arguments].nil? ||
63+
!@options[:env_variables].nil? || !@options[:exact_match_excluded_previews].nil? ||
64+
!@options[:regex_excluded_previews].nil?)
65+
Logger.warn 'All options are ignored when using interactive mode'
66+
end
67+
end
68+
69+
def run_interactive_mode
70+
prompt = TTY::Prompt.new
71+
72+
override_config = false
73+
if File.exist?('emerge_config.yml')
74+
Logger.warn 'There is already a emerge_config.yml file.'
75+
prompt.yes?('Do you want to overwrite it?', default: false) do |answer|
76+
override_config = true if answer
77+
end
78+
end
79+
80+
if !override_config && File.exist?('emerge_config.yml')
81+
config = YAML.load_file('emerge_config.yml')
82+
config['snapshots']['ios']['runSettings'] = []
83+
else
84+
config = {
85+
'version' => 2.0,
86+
'snapshots' => {
87+
'ios' => {
88+
'runSettings' => []
89+
}
90+
}
91+
}
92+
end
93+
94+
Logger.info 'Creating a new config file'
95+
96+
end_config = false
97+
loop do
98+
os_version = get_os_version(prompt)
99+
100+
excluded_previews = get_array_from_user(prompt, EXCLUDED_PREVIEW_PROMPT, EXCLUDED_PREVIEW_FINISH_PROMPT)
101+
excluded_regex_previews = get_array_from_user(prompt, EXCLUDED_REGEX_PREVIEW_PROMPT,
102+
EXCLUDED_REGEX_PREVIEW_FINISH_PROMPT)
103+
arguments_array = get_array_from_user(prompt, ARGUMENTS_PROMPT, ARGUMENTS_FINISH_PROMPT)
104+
env_variables_array = get_array_from_user(prompt, ENV_VARIABLES_PROMPT, ENV_VARIABLES_FINISH_PROMPT)
105+
106+
excluded = get_parsed_previews(excluded_previews, excluded_regex_previews)
107+
env_variables = get_parsed_env_variables(env_variables_array)
108+
109+
os_settings = {
110+
'osVersion' => os_version,
111+
'excludedPreviews' => excluded,
112+
'envVariables' => env_variables,
113+
'arguments' => arguments_array
114+
}
115+
show_config(os_settings)
116+
save = prompt.yes?('Do you want to save this setting?')
117+
config['snapshots']['ios']['runSettings'].push(os_settings) if save
118+
119+
end_config = !prompt.yes?('Do you want to continue adding more settings?')
120+
break if end_config
121+
end
122+
123+
File.write('emerge_config.yml', config.to_yaml)
124+
Logger.info 'Configuration file created successfully!'
125+
end
126+
127+
def run_non_interactive_mode
128+
config = {}
129+
if File.exist?('emerge_config.yml')
130+
config = YAML.load_file('emerge_config.yml')
131+
if !@options[:clear] && !config['snapshots'].nil? && !config['snapshots']['ios'].nil? &&
132+
!config['snapshots']['ios']['runSettings'].nil?
133+
raise 'There is already a configuration file with settings. Use the --clear flag to overwrite it.'
134+
end
135+
136+
config['snapshots']['ios']['runSettings'] = []
137+
138+
else
139+
config = {
140+
'version' => 2.0,
141+
'snapshots' => {
142+
'ios' => {
143+
'runSettings' => []
144+
}
145+
}
146+
}
147+
end
148+
149+
excluded_previews = get_parsed_previews(@options[:exact_match_excluded_previews] || [],
150+
@options[:regex_excluded_previews] || [])
151+
env_variables = get_parsed_env_variables(@options[:env_variables] || [])
152+
153+
os_version = @options[:os_version]
154+
if os_version.nil?
155+
Logger.warn 'No OS version was provided, defaulting to 17.5'
156+
os_version = '17.5'
157+
end
158+
159+
os_settings = {
160+
'osVersion' => os_version,
161+
'excludedPreviews' => excluded_previews,
162+
'envVariables' => env_variables,
163+
'arguments' => @options[:launch_arguments] || []
164+
}
165+
config['snapshots']['ios']['runSettings'].push(os_settings)
166+
File.write('emerge_config.yml', config.to_yaml)
167+
Logger.info 'Configuration file created successfully!'
168+
show_config(os_settings)
169+
end
170+
171+
def get_os_version(prompt)
172+
os_version = prompt.select('Select the OS version you want to run the tests on') do |answer|
173+
AVAILABLE_OS_VERSIONS.each do |version|
174+
answer.choice version, version.to_f
175+
end
176+
answer.choice 'Custom', 'custom'
177+
end
178+
os_version = prompt.ask('Enter the OS version you want to run the tests on') if os_version == 'custom'
179+
os_version
180+
end
181+
182+
def get_array_from_user(prompt, first_prompt_message, second_prompt_message)
183+
continue = prompt.yes?(first_prompt_message)
184+
return [] if !continue
185+
array = []
186+
loop do
187+
item = prompt.ask(second_prompt_message)
188+
if item == '' || item.nil?
189+
continue = false
190+
else
191+
array.push(item)
192+
end
193+
break unless continue
194+
end
195+
array
196+
end
197+
198+
def show_config(config)
199+
table = TTY::Table.new(
200+
header: %w[Key Value],
201+
rows: config.to_a
202+
)
203+
puts table.render(:ascii)
204+
end
205+
206+
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+
})
213+
end
214+
previews_regex.each do |preview|
215+
excluded.push({
216+
'type' => 'regex',
217+
'value' => preview
218+
})
219+
end
220+
excluded
221+
end
222+
223+
def get_parsed_env_variables(env_variables)
224+
env_variables_array_fixed = []
225+
env_variables.each do |env_variable|
226+
key, value = env_variable.split('=')
227+
env_variables_array_fixed.push({
228+
'key' => key, 'value' => value
229+
})
230+
end
231+
end
232+
end
233+
end
234+
end
235+
end

lib/emerge_cli.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require_relative './commands/upload/snapshots/client_libraries/paparazzi'
55
require_relative './commands/upload/snapshots/client_libraries/default'
66
require_relative './commands/integrate/fastlane'
7+
require_relative './commands/config/snapshots/snapshots_ios'
78

89
require_relative './utils/git_info_provider'
910
require_relative './utils/git_result'
@@ -26,6 +27,10 @@ module EmergeCLI
2627
register 'integrate' do |prefix|
2728
prefix.register 'fastlane-ios', Commands::Integrate::Fastlane, aliases: ['i']
2829
end
30+
31+
register 'configure' do |prefix|
32+
prefix.register 'snapshots-ios', Commands::Config::SnapshotsIOS, aliases: ['c']
33+
end
2934
end
3035

3136
# By default the log level is INFO, but can be overridden by the --debug flag
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
require 'test_helper'
2+
3+
module EmergeCLI
4+
module Commands
5+
module Config
6+
class SnapshotsIOSTest < Minitest::Test
7+
def setup
8+
@command = EmergeCLI::Commands::Config::SnapshotsIOS.new
9+
end
10+
11+
def teardown
12+
FileUtils.rm_rf('emerge_config.yml') if File.exist?('emerge_config.yml')
13+
end
14+
15+
def test_raises_error_if_no_clear_and_config_exists
16+
File.write('emerge_config.yml', {}.to_yaml)
17+
18+
options = {}
19+
20+
assert_raises(Exception) do
21+
@command.call(**options)
22+
end
23+
end
24+
25+
def test_creates_config_if_no_config_exists
26+
options = {}
27+
28+
@command.call(**options)
29+
30+
assert File.exist?('emerge_config.yml')
31+
32+
full_config = YAML.load_file('emerge_config.yml')
33+
snapshot_config = full_config['snapshots']['ios']['runSettings'][0]
34+
assert_equal '17.5', snapshot_config['osVersion']
35+
assert_equal [], snapshot_config['arguments']
36+
assert_equal [], snapshot_config['envVariables']
37+
assert_equal [], snapshot_config['excludedPreviews']
38+
end
39+
40+
def test_config_is_updated_if_config_exists
41+
previous_config = {
42+
'snapshots' => {
43+
'ios' => {
44+
'runSettings' => [{ 'osVersion' => '17.5' }]
45+
}
46+
}
47+
}
48+
File.write('emerge_config.yml', previous_config.to_yaml)
49+
50+
options = {
51+
os_version: '18.0',
52+
launch_arguments: %w[arg1 arg2],
53+
clear: true
54+
}
55+
56+
@command.call(**options)
57+
58+
assert File.exist?('emerge_config.yml')
59+
60+
full_config = YAML.load_file('emerge_config.yml')
61+
snapshot_config = full_config['snapshots']['ios']['runSettings'][0]
62+
assert_equal '18.0', snapshot_config['osVersion']
63+
assert_equal %w[arg1 arg2], snapshot_config['arguments']
64+
assert_equal [], snapshot_config['envVariables']
65+
assert_equal [], snapshot_config['excludedPreviews']
66+
end
67+
end
68+
end
69+
end
70+
end

0 commit comments

Comments
 (0)