|
| 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 |
0 commit comments