Class: Tddium::TddiumCli
- Inherits:
-
Thor
- Object
- Thor
- Tddium::TddiumCli
- Extended by:
- ParamsHelper
- Includes:
- TddiumConstant
- Defined in:
- lib/tddium/cli/show.rb,
lib/tddium/cli/util.rb,
lib/tddium/cli/suite.rb,
lib/tddium/cli/prompt.rb,
lib/tddium/cli/tddium.rb,
lib/tddium/cli/commands/hg.rb,
lib/tddium/cli/commands/web.rb,
lib/tddium/cli/commands/keys.rb,
lib/tddium/cli/commands/spec.rb,
lib/tddium/cli/commands/stop.rb,
lib/tddium/cli/commands/login.rb,
lib/tddium/cli/commands/rerun.rb,
lib/tddium/cli/commands/suite.rb,
lib/tddium/cli/commands/config.rb,
lib/tddium/cli/commands/github.rb,
lib/tddium/cli/commands/heroku.rb,
lib/tddium/cli/commands/logout.rb,
lib/tddium/cli/commands/server.rb,
lib/tddium/cli/commands/status.rb,
lib/tddium/cli/commands/account.rb,
lib/tddium/cli/commands/activate.rb,
lib/tddium/cli/commands/describe.rb,
lib/tddium/cli/commands/password.rb,
lib/tddium/cli/commands/find_failing.rb
Instance Attribute Summary collapse
-
#scm ⇒ Object
readonly
Returns the value of attribute scm.
-
#user_details ⇒ Object
readonly
Returns the value of attribute user_details.
Class Method Summary collapse
-
.exit_on_failure? ⇒ Boolean
Thor has the wrong default behavior.
Instance Method Summary collapse
- #account ⇒ Object
- #activate ⇒ Object
- #config(scope = "suite") ⇒ Object
- #describe(session_id = nil) ⇒ Object
- #find_failing(*files) ⇒ Object
- #heroku ⇒ Object
-
#initialize(*args) ⇒ TddiumCli
constructor
A new instance of TddiumCli.
- #keys ⇒ Object
- #login(*args) ⇒ Object
- #logout ⇒ Object
- #password ⇒ Object
- #rerun(session_id = nil) ⇒ Object
- #server ⇒ Object
- #spec(*pattern) ⇒ Object
- #status ⇒ Object
- #stop(ls_id = nil) ⇒ Object
- #suite(*argv) ⇒ Object
- #version ⇒ Object
- #web(*args) ⇒ Object
Methods included from ParamsHelper
display, load_params, write_params
Constructor Details
#initialize(*args) ⇒ TddiumCli
Returns a new instance of TddiumCli.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/tddium/cli/tddium.rb', line 29 def initialize(*args) super(*args) # XXX TODO: read host from .tddium file, allow selecting which .tddium "profile" to use cli_opts = [:insecure] ? { :insecure => true } : {} @tddium_client = TddiumClient::InternalClient.new([:host], [:port], [:proto], 1, caller_version, cli_opts) @scm = Tddium::SCM.configure @api_config = ApiConfig.new(@tddium_client, [:host], ) @repo_config = RepoConfig.new @tddium_api = TddiumAPI.new(@api_config, @tddium_client, @scm) # BOTCH: fugly @api_config.set_api(@tddium_api) end |
Instance Attribute Details
#scm ⇒ Object (readonly)
Returns the value of attribute scm.
8 9 10 |
# File 'lib/tddium/cli/tddium.rb', line 8 def scm @scm end |
#user_details ⇒ Object (readonly)
Returns the value of attribute user_details.
9 10 11 |
# File 'lib/tddium/cli/tddium.rb', line 9 def user_details @user_details end |
Class Method Details
.exit_on_failure? ⇒ Boolean
Thor has the wrong default behavior
79 80 81 |
# File 'lib/tddium/cli/tddium.rb', line 79 def self.exit_on_failure? return true end |
Instance Method Details
#account ⇒ Object
6 7 8 9 10 11 12 13 14 15 |
# File 'lib/tddium/cli/commands/account.rb', line 6 def account user_details = tddium_setup({:scm => false}) if user_details then # User is already logged in, so just display the info show_user_details(user_details) else exit_failure Text::Error::USE_ACTIVATE end end |
#activate ⇒ Object
9 10 11 12 |
# File 'lib/tddium/cli/commands/activate.rb', line 9 def activate say "To activate your account, please visit" say "https://ci.solanolabs.com/" end |
#config(scope = "suite") ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/tddium/cli/commands/config.rb', line 9 def config(scope="suite") tddium_setup({:repo => true, :suite => true}) begin config_details = @tddium_api.get_config_key(scope) show_config_details(scope, config_details['env']) rescue TddiumClient::Error::API => e exit_failure Text::Error::LIST_CONFIG_ERROR rescue Exception => e exit_failure e. end end |
#describe(session_id = nil) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/tddium/cli/commands/describe.rb', line 14 def describe(session_id=nil) tddium_setup({:repo => false}) = '' if !session_id then # params to get the most recent session id on current branch suite_params = { :suite_id => @tddium_api.current_suite_id, :active => false, :limit => 1 } if suite_for_current_branch? sessions = suite_params ? @tddium_api.get_sessions(suite_params) : [] if sessions.empty? then exit_failure Text::Status::NO_INACTIVE_SESSION end session_id = sessions[0]['id'] session_status = sessions[0]['status'].upcase session_commit = sessions[0]['commit'] current_commit = @scm.current_commit if session_commit == current_commit = "equal to your current commit" else cnt_ahead = @scm.number_of_commits(session_commit, current_commit) if cnt_ahead == 0 cnt_behind = @scm.number_of_commits(current_commit, session_commit) = "your workspace is behind by #{cnt_behind} commits" else = "your workspace is ahead by #{cnt_ahead} commits" end end duration = sessions[0]['duration'] start_timeago = "%s ago" % Tddium::TimeFormat.seconds_to_human_time(Time.now - Time.parse(sessions[0]["start_time"])) if duration.nil? finish_timeago = "no info about duration found, started #{start_timeago}" elsif session_status == 'RUNNING' finish_timeago = "in process, started #{start_timeago}" else finish_time = Time.parse(sessions[0]["start_time"]) + duration finish_timeago = "%s ago" % Tddium::TimeFormat.seconds_to_human_time(Time.now - finish_time) end = Text::Status::SESSION_STATUS % [session_commit, , session_status, finish_timeago] end result = @tddium_api.query_session(session_id) filtered = result['session']['tests'] if ![:all] filtered = filtered.select{|x| x['status'] == 'failed'} end if [:type] filtered = filtered.select{|x| x['test_type'].downcase == [:type].downcase} end if [:json] puts JSON.pretty_generate(result['session']) elsif [:names] say filtered.map{|x| x['test_name']}.join(" ") else filtered.sort!{|a,b| [a['test_type'], a['test_name']] <=> [b['test_type'], b['test_name']]} say Text::Process::DESCRIBE_SESSION % [session_id, , [:all] ? 'all' : 'failed'] table = [["Test", "Status", "Duration"], ["----", "------", "--------"]] + filtered.map do |x| [ x['test_name'], x['status'], x['elapsed_time'] ? "#{x['elapsed_time']}s" : "-" ] end print_table table end end |
#find_failing(*files) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/tddium/cli/commands/find_failing.rb', line 7 def find_failing(*files) failing = files.pop if !files.include?(failing) exit_failure "Files have to include the failing file, use the copy helper" elsif files.size < 2 exit_failure "Files have to be more than 2, use the copy helper" elsif !success?([failing]) exit_failure "#{failing} fails when run on it's own" elsif success?(files) exit_failure "tests pass locally" else loop do a = remove_from(files, files.size / 2, :not => failing) b = files - (a - [failing]) status, files = find_failing_set([a, b], failing) if status == :finished say "Fails when #{files.join(", ")} are run together" break elsif status == :continue next else exit_failure "unable to isolate failure to 2 files" end end end end |
#heroku ⇒ Object
10 11 12 13 |
# File 'lib/tddium/cli/commands/heroku.rb', line 10 def heroku say "To activate your heroku account, please visit" say "https://ci.solanolabs.com/" end |
#keys ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/tddium/cli/commands/keys.rb', line 6 def keys user_details = tddium_setup({:scm => false}) begin if user_details then show_third_party_keys_details(user_details) end keys_details = @tddium_api.get_keys show_keys_details(keys_details) rescue TddiumClient::Error::API => e exit_failure Text::Error::LIST_KEYS_ERROR end end |
#login(*args) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/tddium/cli/commands/login.rb', line 9 def login(*args) user_details = tddium_setup({:login => false, :scm => false}) = .dup if args.first && args.first =~ /@/ [:email] ||= args.first elsif args.first # assume cli token [:cli_token] = args.first end if user_details then say Text::Process::ALREADY_LOGGED_IN elsif user = @tddium_api.login_user(:params => @tddium_api.get_user_credentials(), :show_error => true) say Text::Process::LOGGED_IN_SUCCESSFULLY if @scm.repo? then @api_config.populate_branches(@tddium_api.current_branch) end @api_config.write_config else exit_failure end if prompt_missing_ssh_key then say Text::Process::NEXT_STEPS end end |
#logout ⇒ Object
6 7 8 9 10 11 12 |
# File 'lib/tddium/cli/commands/logout.rb', line 6 def logout tddium_setup({:login => false, :scm => false}) @api_config.logout say Text::Process::LOGGED_OUT_SUCCESSFULLY end |
#password ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/tddium/cli/commands/password.rb', line 7 def password user_details = tddium_setup({:scm => false}) params = {} params[:current_password] = HighLine.ask(Text::Prompt::CURRENT_PASSWORD) { |q| q.echo = "*" } params[:password] = HighLine.ask(Text::Prompt::NEW_PASSWORD) { |q| q.echo = "*" } params[:password_confirmation] = HighLine.ask(Text::Prompt::PASSWORD_CONFIRMATION) { |q| q.echo = "*" } begin user_id = user_details["id"] @tddium_api.update_user(user_id, {:user => params}) say Text::Process::PASSWORD_CHANGED rescue TddiumClient::Error::API => e exit_failure Text::Error::PASSWORD_ERROR % e.explanation rescue TddiumClient::Error::Base => e exit_failure e. end end |
#rerun(session_id = nil) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/tddium/cli/commands/rerun.rb', line 11 def rerun(session_id=nil) tddium_setup({:repo => false}) session_id ||= session_id_for_current_suite begin result = @tddium_api.query_session(session_id) rescue TddiumClient::Error::API => e exit_failure Text::Error::NO_SESSION_EXISTS end tests = result['session']['tests'] tests = tests.select{ |t| ['failed', 'error'].include?(t['status']) } tests = tests.map{ |t| t['test_name'] } cmd = "tddium run" cmd += " --max-parallelism=#{[:max_parallelism]}" if [:max_parallelism] cmd += " --org=#{[:account]}" if [:account] cmd += " --force" if [:force] cmd += " #{tests.join(" ")}" say cmd Kernel.exec(cmd) if ![:no_op] end |
#server ⇒ Object
7 8 9 |
# File 'lib/tddium/cli/commands/server.rb', line 7 def server self.class.display end |
#spec(*pattern) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/tddium/cli/commands/spec.rb', line 22 def spec(*pattern) machine_data = {} tddium_setup({:repo => true}) suite_auto_configure unless [:machine] exit_failure unless suite_for_current_branch? if ![:machine] && @tddium_api.get_keys.empty? then warn(Text::Warning::NO_SSH_KEY) end if @scm.changes?() then exit_failure(Text::Error::SCM_CHANGES_NOT_COMMITTED) if ![:force] warn(Text::Warning::SCM_CHANGES_NOT_COMMITTED) end test_execution_params = {} if user_data_file_path = [:user_data_file] then if File.exists?(user_data_file_path) then user_data = File.open(user_data_file_path) { |file| file.read } test_execution_params[:user_data_text] = Base64.encode64(user_data) test_execution_params[:user_data_filename] = File.basename(user_data_file_path) say Text::Process::USING_SPEC_OPTION[:user_data_file] % user_data_file_path else exit_failure Text::Error::NO_USER_DATA_FILE % user_data_file_path end end if max_parallelism = [:max_parallelism] then test_execution_params[:max_parallelism] = max_parallelism say Text::Process::USING_SPEC_OPTION[:max_parallelism] % max_parallelism end test_execution_params[:tag] = [:tag] if [:tag] test_pattern = nil if pattern.is_a?(Array) && pattern.size > 0 then test_pattern = pattern.join(",") end test_pattern ||= [:test_pattern] if test_pattern then say Text::Process::USING_SPEC_OPTION[:test_pattern] % test_pattern end test_exclude_pattern ||= [:test_exclude_pattern] if test_exclude_pattern then say Text::Process::USING_SPEC_OPTION[:test_exclude_pattern] % test_exclude_pattern end tries = 0 while tries < Default::SCM_READY_TRIES do # Call the API to get the suite and its tests suite_details = @tddium_api.get_suite_by_id(@tddium_api.current_suite_id, :session_id => [:session_id]) if suite_details["repoman_current"] == true break else @tddium_api.demand_repoman_account(suite_details["account_id"]) say Text::Process::SCM_REPO_WAIT sleep @api_config.scm_ready_sleep end tries += 1 end exit_failure Text::Error::SCM_REPO_NOT_READY unless suite_details["repoman_current"] update_suite_parameters!(suite_details, [:session_id]) start_time = Time.now new_session_params = { :commits_encoded => read_and_encode_latest_commits, :cache_control_encoded => read_and_encode_cache_control, :cache_save_paths_encoded => read_and_encode_cache_save_paths, :raw_config_file => read_and_encode_config_file } # Create a session # or use an already-created session # session_id = [:session_id] session_data = if session_id && session_id > 0 @tddium_api.update_session(session_id, new_session_params) else @tddium_api.create_session(@tddium_api.current_suite_id, new_session_params) end session_data ||= {} session_id ||= session_data["id"] = {} if [:machine] [:use_private_uri] = true end if !@scm.push_latest(session_data, suite_details, ) then exit_failure Text::Error::SCM_PUSH_FAILED end machine_data[:session_id] = session_id # Register the tests @tddium_api.register_session(session_id, @tddium_api.current_suite_id, test_pattern, test_exclude_pattern) # Start the tests start_test_executions = @tddium_api.start_session(session_id, test_execution_params) num_tests_started = start_test_executions["started"].to_i say Text::Process::STARTING_TEST % num_tests_started.to_s tests_finished = false finished_tests = {} = -100000 test_statuses = Hash.new(0) session_status = nil = nil = nil report = start_test_executions["report"] # In CI mode, just hang up here. The session will continue running. if [:machine] then say Text::Process::BUILD_CONTINUES return end say "" say Text::Process::CHECK_TEST_REPORT % report say Text::Process::TERMINATE_INSTRUCTION say "" # Catch Ctrl-C to interrupt the test Signal.trap(:INT) do say Text::Process::INTERRUPT say Text::Process::CHECK_TEST_STATUS tests_finished = true session_status = "interrupted" end while !tests_finished do current_test_executions = @tddium_api.poll_session(session_id) session_status = current_test_executions['session_status'] , = (, finished_tests, , current_test_executions["messages"]) # Print out the progress of running tests current_test_executions["tests"].each do |test_name, result_params| if finished_tests.size == 0 && result_params["finished"] then say "" say Text::Process::CHECK_TEST_REPORT % report say Text::Process::TERMINATE_INSTRUCTION say "" end if result_params["finished"] && !finished_tests[test_name] test_status = result_params["status"] = case test_status when "passed" then [".", :green, false] when "failed" then ["F", :red, false] when "error" then ["E", nil, false] when "pending" then ["*", :yellow, false] when "skipped" then [".", :yellow, false] else [".", nil, false] end finished_tests[test_name] = test_status = Time.now test_statuses[test_status] += 1 say * end end # XXX time out if all tests are done and the session isn't done. if current_test_executions['session_done'] || (finished_tests.size >= num_tests_started && (Time.now - ) > Default::TEST_FINISH_TIMEOUT) tests_finished = true end sleep(Default::SLEEP_TIME_BETWEEN_POLLS) if !tests_finished end display_alerts(, 'error', Text::Status::SPEC_ERRORS) # Print out the result say "" say Text::Process::RUN_TDDIUM_WEB say "" say Text::Process::FINISHED_TEST % (Time.now - start_time) say "#{finished_tests.size} tests, #{test_statuses["failed"]} failures, #{test_statuses["error"]} errors, #{test_statuses["pending"]} pending, #{test_statuses["skipped"]} skipped" if test_statuses['failed'] > 0 say "" say Text::Process::FAILED_TESTS finished_tests.each do |name, status| next if status != 'failed' say " - #{name}" end say "" end say Text::Process::SUMMARY_STATUS % session_status say "" suite = suite_details.merge({"id" => @tddium_api.current_suite_id}) @api_config.set_suite(suite) @api_config.write_config exit_failure if session_status != 'passed' rescue TddiumClient::Error::API => e exit_failure "Failed due to error: #{e.explanation}" rescue TddiumClient::Error::Base => e exit_failure "Failed due to error: #{e.}" rescue RuntimeError => e exit_failure "Failed due to internal error: #{e.inspect} #{e.backtrace}" end |
#status ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/tddium/cli/commands/status.rb', line 9 def status tddium_setup begin # tddium_setup asserts that we're in a git repo origin_url = @scm.origin_url repo_params = { :active => true, :repo_url => origin_url } if suite_for_current_branch? then status_branch = @tddium_api.current_branch suite_params = { :suite_id => @tddium_api.current_suite_id, :active => false, :limit => 10 } elsif suite_for_default_branch? then status_branch = @tddium_api.default_branch say Text::Error::TRY_DEFAULT_BRANCH % status_branch suite_params = { :suite_id => @tddium_api.default_suite_id, :active => false, :limit => 10 } end if [:json] res = {} res[:running] = { origin_url => @tddium_api.get_sessions(repo_params) } res[:history] = { status_branch => @tddium_api.get_sessions(suite_params) } if suite_params puts JSON.pretty_generate(res) else show_session_details( status_branch, repo_params, Text::Status::NO_ACTIVE_SESSION, Text::Status::ACTIVE_SESSIONS, true ) show_session_details( status_branch, suite_params, Text::Status::NO_INACTIVE_SESSION, Text::Status::INACTIVE_SESSIONS, false ) if suite_params say Text::Process::RERUN_SESSION end rescue TddiumClient::Error::Base => e exit_failure e. end end |
#stop(ls_id = nil) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/tddium/cli/commands/stop.rb', line 6 def stop(ls_id=nil) tddium_setup({:scm => false}) if ls_id begin say "Stoping session #{ls_id} ..." say @tddium_api.stop_session(ls_id)['notice'] rescue end else say 'Stop requires a session id -- e.g. `tddium stop 7869764`' end end |
#suite(*argv) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/tddium/cli/commands/suite.rb', line 19 def suite(*argv) tddium_setup({:repo => true}) params = {} # Load tool options into params tool_cli_populate(, params) begin if [:delete] # Deleting works differently (for now) because api_config can't handle # multiple suites with the same branch name in two different accounts. repo_url = @scm.origin_url if argv.is_a?(Array) && argv.size > 0 branch = argv[0] else branch = @tddium_api.current_branch end suites = @tddium_api.get_suites(:repo_url => repo_url, :branch => branch) if suites.count == 0 exit_failure Text::Error::CANT_FIND_SUITE % [repo_url, branch] elsif suites.count > 1 say Text::Process::SUITE_IN_MULTIPLE_ACCOUNTS % [repo_url, branch] suites.each { |s| say ' ' + s['account'] } account = ask Text::Process::SUITE_IN_MULTIPLE_ACCOUNTS_PROMPT suites = suites.select { |s| s['account'] == account } if suites.count == 0 exit_failure Text::Error::INVALID_ACCOUNT_NAME end end suite = suites.first unless [:non_interactive] yn = ask Text::Process::CONFIRM_DELETE_SUITE % [suite['repo_url'], suite['branch'], suite['account']] unless yn.downcase == Text::Prompt::Response::YES exit_failure Text::Process::ABORTING end end @tddium_api.permanent_destroy_suite(suite['id']) @api_config.delete_suite(suite['branch']) @api_config.write_config elsif @tddium_api.current_suite_id then # Suite ID set in tddium config file current_suite = @tddium_api.get_suite_by_id(@tddium_api.current_suite_id) if [:edit] then update_suite(current_suite, ) else say Text::Process::EXISTING_SUITE, :bold say format_suite_details(current_suite) end @api_config.set_suite(current_suite) @api_config.write_config else # Need to find or construct the suite (and repo) params[:branch] = @scm.current_branch params[:repo_url] = @scm.origin_url params[:repo_name] = @scm.repo_name params[:scm] = @scm.scm_name say Text::Process::NO_CONFIGURED_SUITE % [params[:repo_name], params[:branch]] prompt_suite_params(, params) params.each do |k,v| params.delete(k) if v == 'disable' end # Create new suite if it does not exist yet say Text::Process::CREATING_SUITE % [params[:repo_name], params[:branch]] new_suite = @tddium_api.create_suite(params) # Save the created suite @api_config.set_suite(new_suite) @api_config.write_config say Text::Process::CREATED_SUITE, :bold say format_suite_details(new_suite) end rescue TddiumClient::Error::Base => e exit_failure(e.explanation) end end |
#version ⇒ Object
74 75 76 |
# File 'lib/tddium/cli/tddium.rb', line 74 def version say VERSION end |
#web(*args) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/tddium/cli/commands/web.rb', line 6 def web(*args) tddium_setup({:login => false, :scm => false}) session_id = args.first if session_id then fragment = "1/reports/#{session_id.to_i}" if session_id =~ /^[0-9]+$/ end fragment ||= 'latest' begin Launchy.open("#{[:proto]}://#{[:host]}/#{fragment}") rescue Launchy::Error => e exit_failure e. end end |