solano 1.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +15 -0
  2. data/bin/solano +29 -0
  3. data/bin/tddium +29 -0
  4. data/lib/solano.rb +19 -0
  5. data/lib/solano/agent.rb +3 -0
  6. data/lib/solano/agent/solano.rb +128 -0
  7. data/lib/solano/cli.rb +25 -0
  8. data/lib/solano/cli/api.rb +368 -0
  9. data/lib/solano/cli/commands/account.rb +50 -0
  10. data/lib/solano/cli/commands/activate.rb +16 -0
  11. data/lib/solano/cli/commands/api.rb +15 -0
  12. data/lib/solano/cli/commands/config.rb +78 -0
  13. data/lib/solano/cli/commands/console.rb +85 -0
  14. data/lib/solano/cli/commands/describe.rb +104 -0
  15. data/lib/solano/cli/commands/find_failing.rb +64 -0
  16. data/lib/solano/cli/commands/heroku.rb +17 -0
  17. data/lib/solano/cli/commands/hg.rb +48 -0
  18. data/lib/solano/cli/commands/keys.rb +81 -0
  19. data/lib/solano/cli/commands/login.rb +37 -0
  20. data/lib/solano/cli/commands/logout.rb +14 -0
  21. data/lib/solano/cli/commands/password.rb +26 -0
  22. data/lib/solano/cli/commands/rerun.rb +59 -0
  23. data/lib/solano/cli/commands/server.rb +21 -0
  24. data/lib/solano/cli/commands/spec.rb +401 -0
  25. data/lib/solano/cli/commands/status.rb +117 -0
  26. data/lib/solano/cli/commands/stop.rb +19 -0
  27. data/lib/solano/cli/commands/suite.rb +110 -0
  28. data/lib/solano/cli/commands/support.rb +24 -0
  29. data/lib/solano/cli/commands/web.rb +29 -0
  30. data/lib/solano/cli/config.rb +246 -0
  31. data/lib/solano/cli/params_helper.rb +66 -0
  32. data/lib/solano/cli/prompt.rb +128 -0
  33. data/lib/solano/cli/show.rb +136 -0
  34. data/lib/solano/cli/solano.rb +208 -0
  35. data/lib/solano/cli/suite.rb +104 -0
  36. data/lib/solano/cli/text_helper.rb +16 -0
  37. data/lib/solano/cli/timeformat.rb +21 -0
  38. data/lib/solano/cli/util.rb +132 -0
  39. data/lib/solano/constant.rb +581 -0
  40. data/lib/solano/scm.rb +18 -0
  41. data/lib/solano/scm/configure.rb +37 -0
  42. data/lib/solano/scm/git.rb +349 -0
  43. data/lib/solano/scm/git_log_parser.rb +67 -0
  44. data/lib/solano/scm/hg.rb +263 -0
  45. data/lib/solano/scm/hg_log_parser.rb +66 -0
  46. data/lib/solano/scm/scm.rb +119 -0
  47. data/lib/solano/scm/scm_stub.rb +9 -0
  48. data/lib/solano/scm/url.rb +75 -0
  49. data/lib/solano/script.rb +12 -0
  50. data/lib/solano/script/git-remote-hg +1258 -0
  51. data/lib/solano/ssh.rb +66 -0
  52. data/lib/solano/util.rb +63 -0
  53. data/lib/solano/version.rb +5 -0
  54. metadata +413 -0
@@ -0,0 +1,104 @@
1
+ # Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
2
+
3
+ module Solano
4
+ class SolanoCli < Thor
5
+ protected
6
+
7
+ def update_suite(suite, options)
8
+ params = {}
9
+ prompt_suite_params(options, params, suite)
10
+
11
+ ask_or_update = lambda do |key, text, default|
12
+ params[key] = prompt(text, options[key], suite.fetch(key.to_s, default), options[:non_interactive])
13
+ end
14
+
15
+ ask_or_update.call(:campfire_room, Text::Prompt::CAMPFIRE_ROOM, '')
16
+ ask_or_update.call(:hipchat_room, Text::Prompt::HIPCHAT_ROOM, '')
17
+
18
+ @solano_api.update_suite(suite['id'], params)
19
+ say Text::Process::UPDATED_SUITE
20
+ end
21
+
22
+ def suite_auto_configure
23
+ # Did the user set a configuration option on the command line?
24
+ # If so, auto-configure a new suite and re-configure an existing one
25
+ user_config = options.member?(:tool)
26
+
27
+ current_suite_id = @solano_api.current_suite_id
28
+ if current_suite_id && !user_config then
29
+ current_suite = @solano_api.get_suite_by_id(current_suite_id)
30
+ else
31
+ params = Hash.new
32
+ params[:branch] = @scm.current_branch
33
+ params[:repo_url] = @scm.origin_url
34
+ params[:repo_name] = @scm.repo_name
35
+ params[:scm] = @scm.scm_name
36
+ if options[:account] && !params.member?(:account_id) then
37
+ account_id = @solano_api.get_account_id(options[:account])
38
+ params[:account_id] = account_id if account_id
39
+ end
40
+
41
+ tool_cli_populate(options, params)
42
+ defaults = {}
43
+
44
+ prompt_suite_params(options.merge({:non_interactive => true}), params, defaults)
45
+
46
+ # Create new suite if it does not exist yet
47
+ say Text::Process::CREATING_SUITE % [params[:repo_name], params[:branch]]
48
+
49
+ current_suite = @solano_api.create_suite(params)
50
+
51
+ # Save the created suite
52
+ @api_config.set_suite(current_suite)
53
+ @api_config.write_config
54
+ end
55
+ return current_suite
56
+ end
57
+
58
+ def format_suite_details(suite)
59
+ # Given an API response containing a "suite" key, compose a string with
60
+ # important information about the suite
61
+ solano_deploy_key_file_name = @api_config.solano_deploy_key_file_name
62
+ details = ERB.new(Text::Status::SUITE_DETAILS).result(binding)
63
+ details
64
+ end
65
+
66
+ def suite_for_current_branch?
67
+ return true if @solano_api.current_suite_id
68
+ say Text::Error::NO_SUITE_EXISTS % @scm.current_branch
69
+ false
70
+ end
71
+
72
+ def suite_for_default_branch?
73
+ return true if @solano_api.default_suite_id
74
+ say Text::Error::NO_SUITE_EXISTS % @scm.default_branch
75
+ false
76
+ end
77
+
78
+ # repo_config_file has authority over solano.yml now
79
+ # Update the suite parameters from solano.yml
80
+ #def update_suite_parameters!(current_suite, session_id=nil)
81
+ #end
82
+
83
+ def suite_remembered_option(options, key, default, &block)
84
+ remembered = false
85
+ if options[key] != default
86
+ result = options[key]
87
+ elsif remembered = current_suite_options[key.to_s]
88
+ result = remembered
89
+ remembered = true
90
+ else
91
+ result = default
92
+ end
93
+
94
+ if result then
95
+ msg = Text::Process::USING_SPEC_OPTION[key] % result
96
+ msg += Text::Process::REMEMBERED if remembered
97
+ msg += "\n"
98
+ say msg
99
+ yield result if block_given?
100
+ end
101
+ result
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
2
+
3
+ module Solano
4
+ module TextHelper
5
+ # borrowed from rails/ActionView::Helpers
6
+ def pluralize(count, singular, plural = nil)
7
+ word = if (count == 1 || count =~ /^1(\.0+)?$/)
8
+ singular
9
+ else
10
+ plural || "#{singular}s"
11
+ end
12
+
13
+ "#{count || 0} #{word}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
2
+
3
+ module Solano
4
+ module TimeFormat
5
+ extend Solano::TextHelper
6
+
7
+ def self.seconds_to_human_time(seconds)
8
+ return '-' if seconds.nil?
9
+ seconds = seconds.to_time if seconds.respond_to?(:to_time)
10
+ seconds = seconds.abs.round
11
+ return "0 secs" if seconds == 0
12
+ [[60, :sec], [60, :min], [24, :hr], [10000, :day]].map{ |count, name|
13
+ if seconds > 0
14
+ seconds, n = seconds.divmod(count)
15
+ pluralize(n.to_i, name.to_s)
16
+ end
17
+ }.compact.reverse[0..1].join(' ')
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,132 @@
1
+ # Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
2
+
3
+ module Solano
4
+ class SolanoCli < Thor
5
+ protected
6
+
7
+ def set_shell
8
+ if !$stdout.tty? || !$stderr.tty? then
9
+ @shell = Thor::Shell::Basic.new
10
+ end
11
+ end
12
+
13
+ def tool_cli_populate(options, params)
14
+ if options[:tool].is_a?(Hash) then
15
+ options[:tool].each_pair do |key, value|
16
+ params[key.to_sym] = value
17
+ end
18
+ end
19
+ end
20
+
21
+ def tool_version(tool)
22
+ key = "#{tool}_version".to_sym
23
+ result = @repo_config[key]
24
+
25
+ if result
26
+ say Text::Process::CONFIGURED_VERSION % [tool, result, @repo_config.config_filename]
27
+ return result
28
+ end
29
+
30
+ begin
31
+ result = `#{tool} -v`.strip
32
+ rescue Errno::ENOENT
33
+ exit_failure("#{tool} is not on PATH; please install and try again")
34
+ end
35
+ say Text::Process::DEPENDENCY_VERSION % [tool, result]
36
+ result
37
+ end
38
+
39
+ def sniff_ruby_version_rvmrc(rvmrc)
40
+ ruby_version = nil
41
+ File.open(rvmrc, 'r') do |file|
42
+ file.each_line do |line|
43
+ line.sub!(/^\s+/, '')
44
+ next unless line =~ /^rvm/
45
+ fields = Shellwords.shellsplit(line)
46
+ fields.each do |field|
47
+ if field =~ /^(ree|1[.][89])/ then
48
+ ruby_version = field.sub(/@.*/, '')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ return ruby_version
54
+ end
55
+
56
+ def sniff_ruby_version
57
+ ruby_version = @repo_config["ruby_version"]
58
+ return ruby_version unless ruby_version.nil? || ruby_version.to_s.empty?
59
+
60
+ if !options[:machine] then
61
+ scm_root = @scm.root
62
+ if scm_root then
63
+ rvmrc = File.join(scm_root, '.rvmrc')
64
+ ruby_version_path = File.join(scm_root, '.ruby_version')
65
+ if File.exists?(ruby_version_path) then
66
+ ruby_version = sniff_ruby_version_rvmrc(ruby_version)
67
+ elsif File.exists?(rvmrc) then
68
+ ruby_version = sniff_ruby_version_rvmrc(rvmrc)
69
+ warn("Detected ruby #{ruby_version} in .rvmrc; make sure patch level is correct")
70
+ end
71
+ end
72
+ end
73
+ return ruby_version
74
+ end
75
+
76
+ def normalize_bundler_version(bundler_version)
77
+ if !bundler_version.nil? then
78
+ bundler_version.chomp!
79
+ bundler_version =~ /Bundler version (.*)\z/
80
+ bundler_version = $1
81
+ end
82
+ return bundler_version
83
+ end
84
+
85
+ def ssh_key_fingerprint(pubkey)
86
+ tmp = Tempfile.new('ssh-pub')
87
+ tmp.write(pubkey)
88
+ tmp.close
89
+ fingerprint = nil
90
+ IO.popen("ssh-keygen -lf #{tmp.path}") do |io|
91
+ fingerprint = io.read
92
+ # Keep just bits and fingerprint
93
+ if fingerprint then
94
+ fingerprint.chomp!
95
+ fingerprint = fingerprint.split(/\s+/)[0..1].join(' ')
96
+ end
97
+ end
98
+ tmp.unlink
99
+
100
+ return fingerprint
101
+ end
102
+
103
+ def warn(msg='')
104
+ STDERR.puts("WARNING: #{msg}")
105
+ end
106
+
107
+ def exit_failure(msg='')
108
+ abort msg
109
+ end
110
+
111
+ def display_message(message, prefix=' ---> ')
112
+ color = case message["level"]
113
+ when "error" then :red
114
+ when "warn" then :yellow
115
+ else nil
116
+ end
117
+ print prefix
118
+ say message["text"].rstrip, color
119
+ end
120
+
121
+ def display_alerts(messages, level, heading)
122
+ return unless messages
123
+ interest = messages.select{|m| [level].include?(m['level'])}
124
+ if interest.size > 0
125
+ say heading
126
+ interest.each do |m|
127
+ display_message(m, '')
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,581 @@
1
+ # Copyright (c) 2011-2016 Solano Labs All Rights Reserved
2
+
3
+ module SolanoConstant
4
+
5
+ module Dependency
6
+ VERSION_REGEXP = /([\d\.]+)/
7
+ end
8
+
9
+ module Default
10
+ SLEEP_TIME_BETWEEN_POLLS = 2
11
+
12
+ ENVIRONMENT = "production"
13
+ SSH_FILE = "~/.ssh/id_rsa.pub"
14
+ SUITE_TEST_PATTERN = "features/**.feature, spec/**_spec.rb, spec/features/**.feature, test/**_test.rb"
15
+ SSH_OUTPUT_DIR = "~/.ssh/"
16
+
17
+ GIT_SERVER = "git.solanolabs.com"
18
+ READY_TRIES = 3
19
+ SCM_READY_TRIES = 18
20
+ SCM_READY_SLEEP = 10
21
+ TEST_FINISH_TIMEOUT = 15 * 60 # 15 minutes
22
+
23
+ PARAMS_PATH = "#{ENV['HOME']}/.solano-server"
24
+ end
25
+
26
+ module Config
27
+ REMOTE_NAME = "solano"
28
+ HG_IGNORE = ".hgignore"
29
+ GIT_IGNORE = ".gitignore"
30
+ CONFIG_PATHS = ["solano.yml",
31
+ "config/solano.yml"
32
+ ]
33
+ CONFIG_PATHS_DEPRECATED = ["tddium.yml",
34
+ "config/tddium.yml",
35
+ "config/tddium.cfg"
36
+ ]
37
+ EMBEDDED_SCRIPT_PATH = File.expand_path(File.join("..", "script"), __FILE__)
38
+ end
39
+
40
+ module Api
41
+ module Path
42
+ SUITES = "suites"
43
+ SESSIONS = "sessions"
44
+ REPORTS = "reports"
45
+ USERS = "users"
46
+ SIGN_IN = "#{USERS}/sign_in"
47
+ TEST_EXECUTIONS = "test_executions"
48
+ QUERY_TEST_EXECUTIONS = "#{TEST_EXECUTIONS}/query"
49
+ REGISTER_TEST_EXECUTIONS = "#{TEST_EXECUTIONS}/register"
50
+ START_TEST_EXECUTIONS = "#{TEST_EXECUTIONS}/start"
51
+ REPO_SNAPSHOT = "repo_snapshots"
52
+ REPORT_TEST_EXECUTIONS = "#{TEST_EXECUTIONS}/report"
53
+ SESSION_PATCH = "session_patches"
54
+ ACCOUNT_USAGE_BY_ACCOUNT = "accounts/usage_by_account"
55
+ MEMBERSHIPS = "memberships"
56
+ INSTANCES = "instances"
57
+ KEYS = "keys"
58
+ CONFIG = "env"
59
+ ACCOUNTS = "accounts"
60
+ REPOS = "repos"
61
+ end
62
+ end
63
+
64
+ module License
65
+ FILE_NAME = File.expand_path(File.join("..", "..", "..", "LICENSE.txt"), __FILE__)
66
+ end
67
+
68
+ module Text
69
+ module Prompt
70
+ module Response
71
+ YES = "y"
72
+ DISABLE = 'disable'
73
+ end
74
+ SSH_KEY = "Enter your ssh key or press 'Return'. Using '%s' by default:"
75
+ SUITE_NAME = "Enter a repo name or press 'Return'. Using '%s' by default:"
76
+ EMAIL = "Enter your email address: "
77
+ CURRENT_PASSWORD = "Enter your old password: "
78
+ PASSWORD = "Enter password: "
79
+ NEW_PASSWORD = "Enter a new password: "
80
+ PASSWORD_CONFIRMATION = "Confirm your password: "
81
+ INVITATION_TOKEN = "Enter your activation token:"
82
+ TEST_PATTERN = "Enter a pattern or press 'Return'. Using '%s' by default:"
83
+ CI_PULL_URL = "Enter git URL to pull from (default '%s') or enter 'disable':"
84
+ CI_PUSH_URL = "Enter git URL to push to (default '%s') or enter 'disable':"
85
+ CAMPFIRE_ROOM = "Custom Campfire room for this suite (current: '%s') or enter 'disable':"
86
+ HIPCHAT_ROOM = "Custom HipChat room for this suite (current: '%s') or enter 'disable':"
87
+ ACCOUNT = "Enter the organization to create the suite under:"
88
+ ACCOUNT_DEFAULT = "Enter the organization to create the suite under (default: '%s'):"
89
+ end
90
+
91
+ module Warning
92
+ USE_PASSWORD_TOKEN = "If you signed up with Github, use token from web dashboard as password"
93
+ HG_VERSION = "Unsupported hg version: %s"
94
+ HG_PATHS_DEFAULT_NOT_URI = "hg paths default not a URI"
95
+ HG_GIT_MIRROR_MISSING =<<EOF
96
+
97
+ * The hg <-> git mirror is missing.
98
+
99
+ Please run `solano hg:mirror` to create the mirror for the first time.
100
+
101
+ (Note: it may take several minutes, or even an hour, for hg:mirror to complete,
102
+ depending on how large your repo is. Rest assured, you'll only need to run hg:mirror once.)
103
+
104
+ EOF
105
+ GIT_VERSION_FOR_PATCH =<<EOF
106
+ Patching requires a newer version of git. Please update to git 1.8+ or contact support at support@solanolabs.com
107
+ See http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info on patching
108
+ EOF
109
+ GIT_VERSION = "Unsupported git version: %s"
110
+ SCM_CHANGES_NOT_COMMITTED = "There are uncommitted changes in the local repository"
111
+ SCM_UNABLE_TO_DETECT = "Unable to detect uncommitted changes"
112
+ YAML_PARSE_FAILED = "Unable to parse %s as YAML"
113
+ TEST_CONFIGS_MUST_BE_LIST = "The test_configs section of solano.yml must be a list of configurations"
114
+ NO_SSH_KEY =<<EOF
115
+ You have not set an ssh key for your user. Please add an ssh key using `solano keys:add` or visit http://ci.solanolabs.com/user_settings/ssh_keys
116
+ EOF
117
+ SAME_SNAPSHOT_COMMIT = "Snapshot commit is the same as HEAD"
118
+ EMPTY_PATCH = "Patch not created because it would have been empty. Most likely the commit exists in the snapshot already"
119
+ end
120
+
121
+ module Process
122
+ SSH_KEY_NEEDED = "\nIt looks like you haven't authorized an SSH key to use with Solano CI.\n\n"
123
+ DEFAULT_KEY_ADDED = "SSH key authorized."
124
+ NO_KEYS = "No authorized keys."
125
+ ADD_KEYS_ADD = "Adding key '%s'"
126
+ ADD_KEYS_ADD_DONE =<<EOF
127
+ Authorized key '%s'.
128
+
129
+ Assuming your private key is in %s, you can just add the following
130
+ to ~/.ssh/config to use this new key with Solano CI:
131
+
132
+ # Solano CI SSH Config
133
+ Host %s
134
+ IdentityFile %s
135
+ IdentitiesOnly yes
136
+ EOF
137
+ ADD_KEYS_GENERATE = "Generating key '%s'"
138
+ ADD_KEYS_GENERATE_DONE =<<EOF
139
+ Generated and authorized key '%s'.
140
+
141
+ Append the following to ~/.ssh/config to use this new key with Solano CI:
142
+
143
+ # Solano CI SSH Config
144
+ Host %s
145
+ IdentityFile %s
146
+ IdentitiesOnly yes
147
+ EOF
148
+ REMOVE_KEYS = "Removing key '%s'"
149
+ REMOVE_KEYS_DONE = "Removed key '%s'"
150
+
151
+ NO_CONFIG = "No environment variables configured."
152
+ ADD_CONFIG = "Adding config %s=%s to %s"
153
+ ADD_CONFIG_DONE = "Added config %s=%s to %s"
154
+ REMOVE_CONFIG = "Removing config '%s' from %s"
155
+ REMOVE_CONFIG_DONE = "Removed config '%s' from %s"
156
+ CONFIG_EDIT_COMMANDS =<<EOF
157
+
158
+ Use `solano config:add <scope> <key> <value>` to set a config key.
159
+ Use `solano config:remove <scope> <key>` to remove a key.
160
+
161
+ EOF
162
+ KEYS_EDIT_COMMANDS =<<EOF
163
+
164
+ Use `solano keys:add` to generate and authorize a new SSH keypair.
165
+ Use `solano keys:remove` to remove an authorized key from Solano CI.
166
+
167
+ Use `ssh-keygen -lf <filename>` to print fingerprint of an existing public key.
168
+
169
+ EOF
170
+ TEST_PATTERN_INSTRUCTIONS =<<EOF
171
+
172
+ >>> Solano CI selects tests to run by default (e.g., in CI) by matching against a
173
+ list of Ruby glob patterns. Use "," to join multiple globs.
174
+
175
+ You can instead specify a list of test patterns in config/solano.yml.
176
+
177
+ Read more here: https://docs.solanolabs.com/
178
+
179
+ EOF
180
+ NO_CONFIGURED_SUITE = "Looks like you haven't configured Solano CI on this computer for %s/%s...\n"
181
+ FOUND_EXISTING_SUITE = "Found a suite in Solano CI for\n\n%s\n\n(on branch %s)."
182
+ TERMINATE_INSTRUCTION = ">>> Press Ctrl-C to stop waiting. Tests will continue running.\n"
183
+ INTERRUPT = "Interrupted"
184
+ SCM_PUSH = ">>> Pushing changes to Solano CI..."
185
+ SCM_REPO_WAIT = ">>> Waiting for your repository to be prepared. Sleeping for 10 seconds..."
186
+ STARTING_TEST = ">>> Starting Session with %s tests..."
187
+ CHECK_TEST_STATUS = ">>> Use 'solano status' to check on pending jobs"
188
+ FINISHED_TEST = "Finished in %s seconds"
189
+ RUN_SOLANO_WEB = "\n>>> Run `solano web` to open the latest test results in your browser.\n"
190
+ CHECK_TEST_REPORT = ">>> To view results, visit: %s"
191
+ FAILED_TESTS = "Failed tests:"
192
+ SUMMARY_STATUS = "Final result: %s."
193
+ EXISTING_SUITE = "\nCurrent suite:\n"
194
+ USING_EXISTING_SUITE = "Using suite '%s/%s'."
195
+ CREATING_SUITE = "Creating suite '%s/%s'. This will take a few seconds."
196
+ CREATING_SUITE_CI_DISABLED = "Disabling automatic CI for this new branch."
197
+ CREATING_REPO_SNAPSHOT = "Creating a snapshot from %s"
198
+ CREATING_REPO_SNAPSHOT_BRANCH = "Creating a snapshot from %s, based on branch %s"
199
+ CREATED_SUITE = "\nCreated suite.\n"
200
+ PASSWORD_CONFIRMATION_INCORRECT = "Password confirmation incorrect"
201
+ PASSWORD_CHANGED = "Your password has been changed."
202
+ NEXT_STEPS = "
203
+
204
+ Next, you should register your test suite and start tests by running:
205
+
206
+ $ solano run
207
+
208
+ "
209
+ ALREADY_LOGGED_IN = "You're already logged in"
210
+ LOGGED_IN_SUCCESSFULLY = "Logged in successfully"
211
+ LOGGED_OUT_SUCCESSFULLY = "Logged out successfully"
212
+ USING_SPEC_OPTION = {:max_parallelism => "Max number of tests in parallel = %s",
213
+ :user_data_file => "Sending user data from %s",
214
+ :test_pattern => "Selecting tests that match '%s'",
215
+ :test_exclude_pattern => "Excluding tests that match '%s'"}
216
+ REMEMBERED = " (Remembered value)"
217
+ UPDATED_SUITE = "Updated suite successfully."
218
+ UPDATED_TEST_PATTERN = "Updated test pattern to '%s'"
219
+ UPDATED_TEST_EXCLUDE_PATTERN = "Updated test exclude pattern to '%s'"
220
+ UPDATED_RUBY_VERSION = "Updated ruby version to '%s'"
221
+ UPDATED_BUNDLER_VERSION = "Updated bundler version to '%s'"
222
+ UPDATED_PYTHON_CONFIG = "Updated Python configuration:\n%s"
223
+ UPDATED_TEST_CONFIGS = "Updated test configurations:\n%s"
224
+ DEPENDENCY_VERSION = "... Detected %s %s"
225
+ CONFIGURED_VERSION = "Configured %s %s from %s"
226
+ CONFIGURED_PATTERN =<<EOF;
227
+ ... Configured test pattern from %s:
228
+
229
+ %s
230
+
231
+ >>> To change the pattern:
232
+ 1. Edit %s
233
+ 2. Run `solano suite --edit` again.
234
+ EOF
235
+ CONFIGURED_EXCLUDE_PATTERN =<<EOF;
236
+ ... Configured test exclude pattern from %s:
237
+
238
+ %s
239
+
240
+ >>> To change the pattern:
241
+ 1. Edit %s
242
+ 2. Run `solano suite --edit` again.
243
+ EOF
244
+ DETECTED_BRANCH = "... Detected branch %s"
245
+ SETUP_CI=<<EOF;
246
+
247
+ >>> To set up Hosted CI, enter a git URL to pull from.
248
+ You can also set a git URL to push to after tests pass.
249
+
250
+ >>> Set both pull and push URLs to 'disable' to disable hosted CI completely.
251
+
252
+ EOF
253
+ SETUP_CAMPFIRE=<<EOF;
254
+
255
+
256
+ EOF
257
+
258
+ ADDING_MEMBER = "Adding %s as %s..."
259
+ ADDED_MEMBER = "Added %s"
260
+ REMOVING_MEMBER = "Removing %s. This may take a few seconds..."
261
+ REMOVED_MEMBER = "Removed %s"
262
+
263
+ USING_ACCOUNT_FROM_FLAG = "Using organization '%s' (from command line)."
264
+ USING_ACCOUNT = "Using organization '%s'."
265
+
266
+ CONFIRM_DELETE_SUITE = <<EOF.rstrip
267
+ Are you sure you want to delete the suite %s/%s
268
+ in organization %s?
269
+ This will delete all sessions associated with this suite, and cannot be un-done.
270
+ y/[n]:
271
+ EOF
272
+ SUITE_IN_MULTIPLE_ACCOUNTS = "The suite %s/%s exists in multiple organization:"
273
+ SUITE_IN_MULTIPLE_ACCOUNTS_PROMPT = "Which organization do you want to delete it from:"
274
+
275
+ ABORTING = "Aborting."
276
+ DESCRIBE_SESSION =<<EOF
277
+
278
+ Session %s%s
279
+ Showing %s tests
280
+
281
+ EOF
282
+ RERUN_SESSION =<<EOF
283
+
284
+ Re-run failures from a session with `solano rerun <session_id>`.
285
+ Extract details of a session with `solano describe <session_id>`.
286
+
287
+ EOF
288
+ OPTIONS_SAVED = 'Options have been successfully saved.'
289
+ NOT_SAVED_OPTIONS = 'There is no server information saved. Run `solano server:set`.'
290
+ BUILD_CONTINUES = 'Session will continue running.'
291
+ USING_PROFILE = "Starting session with profile '%s'"
292
+ VOLUME_OVERRIDE = "Worker volume set to %s"
293
+ USING_SESSION_MANAGER = "Starting session with manager '%s'"
294
+ USING_CUSTOM_USER_ENV_VARS = "Starting session with custom environment variables: %s"
295
+ SNAPSHOT_COMMIT = "Snapshot commit is %s"
296
+ NO_SNAPSHOT = "No snapshot, creating one"
297
+ FORCED_SNAPSHOT = "Forcing snapshot creation"
298
+ SNAPSHOT_URL = "Snapshot url is %s"
299
+ REQUST_PATCH_URL = "Requesting patch url"
300
+ UPLOAD_PATCH = "Uploading patch to %s"
301
+ USING_MASTER = "Found a branch named master, if this is not the correct default branch please run again with --force_snapshot --default_branch=master"
302
+ ATTEMPT_UPSTREAM_PATCH = "Attempting to create a patch from %s"
303
+ CREATING_PATCH =<<EOF
304
+ Creating a Patch by running
305
+ git diff --minimal -p --ignore-space-at-eol --no-prefix %s..%s
306
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info on patching
307
+ EOF
308
+ ASK_FOR_SNAPSHOT =<<EOF
309
+ Since we could not create a patch, we can try creating a snapshot instead. This may take longer to upload, then a patch.
310
+ WARNING this will replace the current snapshot for the Repo.
311
+ (Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info)
312
+ Would you like to attempt snapshot creation?[Y/n]
313
+ EOF
314
+ end # Process
315
+
316
+ module Status
317
+ SPEC_WARNINGS = "\n\n>>> Solano CI Warnings:\n\n"
318
+ SPEC_ERRORS = "\n\n>>> Solano CI Errors:\n"
319
+ NO_SUITE = "You currently do not have any suites"
320
+ ALL_SUITES = "Suites:"
321
+ CURRENT_SUITE = "Current suite: %s"
322
+ CURRENT_SUITE_UNAVAILABLE = "Your current suite is unavailable"
323
+ NO_ACTIVE_SESSION = "There are no running sessions for this repo."
324
+ ACTIVE_SESSIONS = "Your active sessions for this repo%s:"
325
+ NO_INACTIVE_SESSION = "There are no recent sessions on this branch."
326
+ INACTIVE_SESSIONS = "Latest sessions on branch %s:"
327
+ SESSION_DETAIL = " %10.10s %s %s in %s, %s"
328
+ ATTRIBUTE_DETAIL = " %s: %s"
329
+ SEPARATOR = "====="
330
+ USING_SUITE = "\nUsing suite:\n"
331
+ USER_DETAILS =<<EOF;
332
+
333
+ Username: <%=user["email"]%>
334
+ User created: <%=user["created_at"]%>
335
+ EOF
336
+ ACCOUNT_DETAILS =<<EOF;
337
+
338
+ Organization: <%=acct["account"]%>
339
+
340
+ Role: <%=acct["account_role"]%>
341
+ Owner: <%=acct["account_owner"]%>
342
+ Plan: <%=acct["plan"]%>
343
+ <% if acct["trial_remaining"] && acct["trial_remaining"] > 0 %> Trial Period Remaining: <%=acct["trial_remaining"]%> days<% end %>
344
+ <% if acct["account_url"] %> Organization Management URL: <%=acct["account_url"]%><% end %>
345
+ <% if acct["heroku"] %> Heroku Account Linked: <%=acct["heroku_activation_done"]%><% end %>
346
+ <% if acct["third_party_pubkey"] %>
347
+ >>> Authorize the following SSH public key to allow Solano CI's test workers to
348
+ install gems from private git repos or communicate via SSH to your servers:
349
+
350
+ <%= acct["third_party_pubkey"] %>
351
+
352
+ <%end%>
353
+ EOF
354
+ USER_THIRD_PARTY_KEY_DETAILS =<<EOF;
355
+ <% if user["third_party_pubkey"] %>
356
+ >>> Authorize the following SSH public key to allow Solano CI's test workers to
357
+ install gems from private git repos or communicate via SSH to your servers:
358
+
359
+ <%= user["third_party_pubkey"] %>
360
+ <%end%>
361
+ EOF
362
+
363
+ SUITE_DETAILS =<<EOF;
364
+ Organization: <%=suite["account"]%>
365
+ Repo: <%=suite["repo_url"]%>
366
+ Scm: <%=suite["scm"]%>
367
+ Branch: <%=suite["branch"]%>
368
+ Default Test Pattern: <%=suite["test_pattern"]%>
369
+ Ruby Version: <%=suite["ruby_version"]%>
370
+ Rubygems Version: <%=suite["rubygems_version"]%>
371
+ Bundler Version: <%=suite["bundler_version"]%>
372
+ <% if suite["ci_enabled"] %>
373
+ Solano CI is enabled with the following parameters:
374
+
375
+ Pull URL: <%=suite["ci_pull_url"]%>
376
+
377
+ Notifications:
378
+
379
+ <%=suite["ci_notifications"]%>
380
+
381
+ <% if suite["ci_pull_url"] =~ /^git@github.com:(.*).git$/ %>
382
+ >>> Solano CI will pull from your Github repository.
383
+
384
+ Visit https://github.com/<%= $1 %>/admin/keys
385
+ then click "Add another deploy key" and copy and paste this key:
386
+
387
+ <%=suite["ci_ssh_pubkey"]%>
388
+ <% else %>
389
+ >>> Authorize the following SSH key to let Solano CI's pulls and pushes through:
390
+
391
+ <%=suite["ci_ssh_pubkey"]%>
392
+ <% end %><% if suite["ci_push_url"] =~ /^git@heroku.com:(.*).git$/ %>
393
+ >>> Solano CI will push to your Heroku application <%= $1 %>.
394
+ To authorize the key, use the following command:
395
+
396
+ heroku keys:add <%= solano_deploy_key_file_name %> --app <%= $1 %>
397
+ <% end %><% if suite["ci_pull_url"] =~ /^git@github.com:(.*).git$/ %>
398
+ >>> Configure Github to notify Solano CI of your commits with a post-receive hook.
399
+
400
+ Visit https://github.com/<%= $1 %>/admin/hooks#generic_minibucket
401
+ then add the following URL and click "Update Settings":
402
+ <%=suite["hook_uri"]%>
403
+ <% else %>
404
+ >>> In order for Solano CI to know that your repo has changed, you'll need to
405
+ configure a post-commit hook in your Git server.
406
+
407
+ In Unix-based Git repositories, find the repository root and look for
408
+ a shell script in `.git/hooks/post-commit`.
409
+
410
+ To trigger CI builds, POST to the following URL from a post-commit hook:
411
+ <%=suite["hook_uri"]%>
412
+ <% end %>
413
+
414
+ >>> See http://docs.solanolabs.com/ for more information on Solano CI.
415
+ >>> You can enable Campfire and HipChat notifications from your Solano CI Dashboard.
416
+ <% end %>
417
+ >>> Run 'solano suite --edit' to edit these settings.
418
+ >>> Run 'solano spec' to run tests in this suite.
419
+ EOF
420
+ ACCOUNT_MEMBERS = "Authorized users:"
421
+ KEYS_DETAILS =<<EOF
422
+
423
+ You have authorized the following SSH public keys to communicate with Solano CI:
424
+
425
+ Name Fingerprint
426
+ ------------------ ------------------------------------------------------------
427
+ EOF
428
+ CONFIG_DETAILS =<<EOF
429
+ The following environment variables are set for this %s:
430
+
431
+ EOF
432
+ SESSION_STATUS =<<EOF
433
+
434
+ Session Details:
435
+
436
+ Commit: %s (%s)
437
+ Status: %s
438
+ Finished: %s
439
+
440
+ EOF
441
+ end
442
+
443
+ module Error
444
+ NOT_INITIALIZED = "Solano CI must be initialized. Try 'solano login'"
445
+ OPTIONS_NOT_SAVED = 'Options have not been saved.'
446
+ LIST_CONFIG_ERROR = "Error listing configuration variables"
447
+ ADD_CONFIG_ERROR = "Error setting configuration variable"
448
+ REMOVE_CONFIG_ERROR = "Error removing configuration variable"
449
+ KEY_ALREADY_EXISTS = "Aborting. SSH key already exists: %s"
450
+ KEYGEN_FAILED = "Failed to generate new SSH key for '%s'"
451
+ LIST_API_KEY_ERROR = "Unable to retrieve API key"
452
+ LIST_KEYS_ERROR = "Error listing SSH keys"
453
+ REMOVE_KEYS_ERROR = "Failed to remove key '%s'"
454
+ ADD_KEYS_DUPLICATE = "You already have a key named '%s'"
455
+ ADD_KEY_CONTENT_DUPLICATE = "You already have a key named '%s' with the same content"
456
+ ADD_KEYS_ERROR = "Failed to add key '%s'"
457
+ INVALID_SSH_PUBLIC_KEY = '%s does not appear to be a valid SSH public key'
458
+ INACCESSIBLE_SSH_PUBLIC_KEY = '%s is not accessible: %s'
459
+ INVALID_SOLANO_FILE = ".solano.%s config file is corrupt. Try 'solano login'"
460
+ INVALID_CONFIGURED_PATTERN =<<EOF;
461
+ Configuring test pattern from %s...
462
+
463
+ >>> The test_pattern in %s is not properly formatted. It must be a YAML list.
464
+
465
+ You entered:
466
+
467
+ %s
468
+
469
+ >>> Edit %s and rerun `solano suite --edit`
470
+
471
+ EOF
472
+ SCM_NOT_A_REPOSITORY = "Current working directory is not a suitable repository"
473
+ SCM_NO_ORIGIN = "Origin URI not set; Solano CI requires origin URI to identify repository"
474
+ SCM_REPO_NOT_READY = "Your repository is being prepped. Try again in a minute."
475
+ SCM_PUSH_FAILED = <<EOF;
476
+
477
+ Attempt to push source to Solano CI failed.
478
+
479
+ If you get a "Permission denied (publickey)" message, ensure that SSH is
480
+ configured to send a key you have authorized with Solano CI (Run `solano keys` to
481
+ see a list.)
482
+
483
+ For any other error, contact us at: support@solanolabs.com
484
+
485
+
486
+ EOF
487
+ SCM_CHANGES_NOT_COMMITTED =<<EOF
488
+ There are uncommitted changes in the local repository.
489
+
490
+ Commit changes before running 'solano spec'.
491
+
492
+ Use 'solano spec --force' to test with only already-committed changes.
493
+ EOF
494
+ SCM_NOT_FOUND = "Solano CI requires git or mercurial which are not on your PATH"
495
+ SCM_NOT_INITIALIZED =<<EOF;
496
+ It doesn't look like you're in a git repo. If you're not, use 'git init' to
497
+ create one.
498
+
499
+ If you are in a git repo and you're still seeing this message,
500
+ you may be using an unsupported version of git.
501
+
502
+ Please email us at support@solanolabs.com with the following trace information:
503
+
504
+ >>>>>>>>>>>>> BEGIN GIT TRACE >>>>>>>>>>>>>>>>>>>>>>>>>
505
+ hg version: #{`hg status 2> /dev/null && hg -q --version 2>&1`}
506
+ git version: #{`git status 2> /dev/null && git --version 2>&1`}
507
+ git status: #{`git status 2> /dev/null && git status 2>&1`}
508
+ git status result: #{ $? }
509
+ git details: #{`git status 2> /dev/null && git status --porcelain 2>&1`}
510
+ git details result: #{ $? }
511
+ >>>>>>>>>>>>> END GIT TRACE >>>>>>>>>>>>>>>>>>>>>>>>>
512
+ EOF
513
+ NO_SESSION_EXISTS = "No session exists for the current branch. Use 'solano run'"
514
+ NO_SUITE_EXISTS = "No suite exists for the branch '%s'. Try running 'solano suite'"
515
+ TRY_DEFAULT_BRANCH = "Getting suites for default '%s' branch."
516
+ NO_USER_DATA_FILE = "User data file '%s' does not exist"
517
+ NO_MATCHING_FILES = "No files match '%s'"
518
+ PASSWORD_ERROR = "Error changing password: %s"
519
+ ADD_MEMBER_ERROR = "Error adding %s: %s"
520
+ REMOVE_MEMBER_ERROR = "Error removing %s: %s"
521
+ USE_ACTIVATE = "Visit 'https://ci.solanolabs.com' to activate your account for the first time."
522
+ INVALID_CREDENTIALS = "Your .solano file has an invalid API key.\nRun `solano logout` and `solano login`, and then try again."
523
+ MISSING_ACCOUNT_OPTION = "You must specify an organization by passing the --org option."
524
+ MISSING_ACCOUNT = "You must specify an organization."
525
+ NOT_IN_ACCOUNT = "You aren't a member of organization %s."
526
+ CANT_FIND_SUITE = "Can't find suite for %s/%s"
527
+ INVALID_ACCOUNT_NAME = "Invalid organization name."
528
+ CANT_INVOKE_COMMAND =<<EOF
529
+ ERROR: could not invoke solano command
530
+ Usage: "solano COMMAND [ARGS] [OPTIONS]". For available commands, run "solano help".
531
+ EOF
532
+ CONFIG_PATHS_COLLISION =<<EOF
533
+ You have both solano.yml and tddium.yml in your repo. We don't support merging the configuration from both of these files, so you'll have to pick one. The solano.yml file will soon be deprecated, so we recommend migrating all of your configuration to solano.yml.
534
+ EOF
535
+ CANNOT_OVERRIDE_PROFILE="Cannot override profile for existing session"
536
+ CANNOT_OVERRIDE_QUEUE="Cannot override queue for existing session"
537
+ COMMAND_DEPRECATED = "This command is deprecated and will be removed in a future version"
538
+ NO_PATCH_URL = "Failed to get Patch URL"
539
+ SNAPSHOT_NOT_SUPPORTED =<<EOF
540
+ ================================================================================================
541
+ Snapshot creation not supported
542
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
543
+ ================================================================================================
544
+ EOF
545
+ PATCH_NOT_SUPPORTED =<<EOF
546
+ ================================================================================================
547
+ Patch creation not supported
548
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
549
+ ================================================================================================
550
+ EOF
551
+ PATCH_CREATION_ERROR = "Solano's current snapshot is based on commit: %s. We could not create a patch for your current state to that patch"
552
+ DEFAULT_BRANCH =<<EOF
553
+ Could not find the default branch, looked for origin/head. We Need the default branch to create a snapshot. Please try again using --default_branch=master
554
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
555
+ EOF
556
+ FAILED_TO_CREATE_SNAPSHOT =<<EOF
557
+ Could not create a repo snapshot, output from command was: %s
558
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
559
+ EOF
560
+ FAILED_TO_CREATE_PATCH = "Could not create a repo patch. Tried to patch based on %s. output from command was: %s"
561
+ ANSWER_NOT_Y =<<EOF
562
+ ================================================================================================
563
+ Since you did not create a snapshot, and we could not create a patch a build can not be started.
564
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
565
+ ================================================================================================
566
+ EOF
567
+ NEED_TO_FORCE =<<EOF
568
+ There is currently not a Solano snapshot for this repo. We tried to create a snapshot based on your local copy of '%s', but it appears that there are unpushed commits on this branch.
569
+ To Ensure the snapshot is usable by other builds please run 'solano run' either after pushing the current commits or use 'solano run --force_snapshot' to create a snapshot from the current state.
570
+ Please see http://docs.solanolabs.com/RunningBuild/snapshots-and-patches/ for more info
571
+ EOF
572
+ end
573
+ end
574
+
575
+ module DisplayedAttributes
576
+ SUITE = %w{repo_url branch test_pattern
577
+ ruby_version bundler_version rubygems_version
578
+ test_scripts test_executions git_repo_uri}
579
+ TEST_EXECUTION = %w{start_time end_time test_execution_stats report}
580
+ end
581
+ end