tddium 1.25.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/tddium +29 -0
- data/lib/tddium.rb +19 -0
- data/lib/tddium/agent.rb +3 -0
- data/lib/tddium/agent/tddium.rb +122 -0
- data/lib/tddium/cli.rb +26 -0
- data/lib/tddium/cli/api.rb +319 -0
- data/lib/tddium/cli/commands/account.rb +49 -0
- data/lib/tddium/cli/commands/activate.rb +14 -0
- data/lib/tddium/cli/commands/config.rb +55 -0
- data/lib/tddium/cli/commands/describe.rb +96 -0
- data/lib/tddium/cli/commands/find_failing.rb +62 -0
- data/lib/tddium/cli/commands/github.rb +53 -0
- data/lib/tddium/cli/commands/heroku.rb +15 -0
- data/lib/tddium/cli/commands/hg.rb +48 -0
- data/lib/tddium/cli/commands/keys.rb +83 -0
- data/lib/tddium/cli/commands/login.rb +37 -0
- data/lib/tddium/cli/commands/logout.rb +14 -0
- data/lib/tddium/cli/commands/password.rb +26 -0
- data/lib/tddium/cli/commands/rerun.rb +50 -0
- data/lib/tddium/cli/commands/server.rb +22 -0
- data/lib/tddium/cli/commands/spec.rb +306 -0
- data/lib/tddium/cli/commands/status.rb +107 -0
- data/lib/tddium/cli/commands/stop.rb +19 -0
- data/lib/tddium/cli/commands/suite.rb +110 -0
- data/lib/tddium/cli/commands/web.rb +22 -0
- data/lib/tddium/cli/config.rb +245 -0
- data/lib/tddium/cli/params_helper.rb +36 -0
- data/lib/tddium/cli/prompt.rb +128 -0
- data/lib/tddium/cli/show.rb +122 -0
- data/lib/tddium/cli/suite.rb +179 -0
- data/lib/tddium/cli/tddium.rb +153 -0
- data/lib/tddium/cli/text_helper.rb +16 -0
- data/lib/tddium/cli/timeformat.rb +21 -0
- data/lib/tddium/cli/util.rb +132 -0
- data/lib/tddium/constant.rb +509 -0
- data/lib/tddium/scm.rb +8 -0
- data/lib/tddium/scm/git.rb +188 -0
- data/lib/tddium/scm/git_log_parser.rb +67 -0
- data/lib/tddium/scm/hg.rb +160 -0
- data/lib/tddium/scm/hg_log_parser.rb +66 -0
- data/lib/tddium/scm/scm.rb +20 -0
- data/lib/tddium/script.rb +12 -0
- data/lib/tddium/script/git-remote-hg +1258 -0
- data/lib/tddium/ssh.rb +66 -0
- data/lib/tddium/util.rb +35 -0
- data/lib/tddium/version.rb +5 -0
- metadata +394 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Tddium
|
4
|
+
class TddiumCli < Thor
|
5
|
+
include TddiumConstant
|
6
|
+
extend ParamsHelper
|
7
|
+
|
8
|
+
attr_reader :scm
|
9
|
+
attr_reader :user_details
|
10
|
+
|
11
|
+
params = self.load_params
|
12
|
+
|
13
|
+
class_option :host, :type => :string,
|
14
|
+
:default => params['host'] || ENV['TDDIUM_CLIENT_HOST'] || "ci.solanolabs.com",
|
15
|
+
:desc => "Solano CI app server hostname"
|
16
|
+
|
17
|
+
class_option :port, :type => :numeric,
|
18
|
+
:default => params['port'] || (ENV['TDDIUM_CLIENT_PORT'].nil? ? nil : ENV['TDDIUM_CLIENT_PORT'].to_i),
|
19
|
+
:desc => "Solano CI app server port"
|
20
|
+
|
21
|
+
class_option :proto, :type => :string,
|
22
|
+
:default => params['proto'] || ENV['TDDIUM_CLIENT_PROTO'] || "https",
|
23
|
+
:desc => "API Protocol"
|
24
|
+
|
25
|
+
class_option :insecure, :type => :boolean,
|
26
|
+
:default => params.key?('insecure') ? params['insecure'] : (ENV['TDDIUM_CLIENT_INSECURE'] != nil),
|
27
|
+
:desc => "Don't verify Solano CI app SSL server certificate"
|
28
|
+
|
29
|
+
def initialize(*args)
|
30
|
+
super(*args)
|
31
|
+
|
32
|
+
# XXX TODO: read host from .tddium file, allow selecting which .tddium "profile" to use
|
33
|
+
cli_opts = options[:insecure] ? { :insecure => true } : {}
|
34
|
+
@tddium_client = TddiumClient::InternalClient.new(options[:host],
|
35
|
+
options[:port],
|
36
|
+
options[:proto],
|
37
|
+
1,
|
38
|
+
caller_version,
|
39
|
+
cli_opts)
|
40
|
+
|
41
|
+
@scm = Tddium::SCM.configure
|
42
|
+
|
43
|
+
@api_config = ApiConfig.new(@tddium_client, options[:host], options)
|
44
|
+
@repo_config = RepoConfig.new
|
45
|
+
@tddium_api = TddiumAPI.new(@api_config, @tddium_client, @scm)
|
46
|
+
|
47
|
+
# BOTCH: fugly
|
48
|
+
@api_config.set_api(@tddium_api)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
require "tddium/cli/commands/account"
|
53
|
+
require "tddium/cli/commands/activate"
|
54
|
+
require "tddium/cli/commands/heroku"
|
55
|
+
require "tddium/cli/commands/login"
|
56
|
+
require "tddium/cli/commands/logout"
|
57
|
+
require "tddium/cli/commands/password"
|
58
|
+
require "tddium/cli/commands/rerun"
|
59
|
+
require "tddium/cli/commands/find_failing"
|
60
|
+
require "tddium/cli/commands/spec"
|
61
|
+
require "tddium/cli/commands/stop"
|
62
|
+
require "tddium/cli/commands/suite"
|
63
|
+
require "tddium/cli/commands/status"
|
64
|
+
require "tddium/cli/commands/keys"
|
65
|
+
require "tddium/cli/commands/config"
|
66
|
+
require 'tddium/cli/commands/describe'
|
67
|
+
require "tddium/cli/commands/web"
|
68
|
+
require 'tddium/cli/commands/github'
|
69
|
+
require 'tddium/cli/commands/hg'
|
70
|
+
require 'tddium/cli/commands/server'
|
71
|
+
|
72
|
+
map "-v" => :version
|
73
|
+
desc "version", "Print the tddium gem version"
|
74
|
+
def version
|
75
|
+
say VERSION
|
76
|
+
end
|
77
|
+
|
78
|
+
# Thor has the wrong default behavior
|
79
|
+
def self.exit_on_failure?
|
80
|
+
return true
|
81
|
+
end
|
82
|
+
|
83
|
+
# Thor prints a confusing message for the "help" command in case an option
|
84
|
+
# follows in the wrong order before the command.
|
85
|
+
# This code patch overwrites this behavior and prints a better error message.
|
86
|
+
# For Thor version >= 0.18.0, release 2013-03-26.
|
87
|
+
if defined? no_commands
|
88
|
+
no_commands do
|
89
|
+
def invoke_command(command, *args)
|
90
|
+
begin
|
91
|
+
super
|
92
|
+
rescue InvocationError
|
93
|
+
if command.name == "help"
|
94
|
+
exit_failure Text::Error::CANT_INVOKE_COMMAND
|
95
|
+
else
|
96
|
+
raise
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
def caller_version
|
106
|
+
"tddium-#{VERSION}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def configured_test_pattern
|
110
|
+
pattern = @repo_config["test_pattern"]
|
111
|
+
|
112
|
+
return nil if pattern.nil? || pattern.empty?
|
113
|
+
return pattern
|
114
|
+
end
|
115
|
+
|
116
|
+
def configured_test_exclude_pattern
|
117
|
+
pattern = @repo_config["test_exclude_pattern"]
|
118
|
+
|
119
|
+
return nil if pattern.nil? || pattern.empty?
|
120
|
+
return pattern
|
121
|
+
end
|
122
|
+
|
123
|
+
def tddium_setup(params={})
|
124
|
+
params[:scm] = !params.member?(:scm) || params[:scm] == true
|
125
|
+
params[:login] = true unless params.member?(:login)
|
126
|
+
params[:repo] = params[:repo] == true
|
127
|
+
params[:suite] = params[:suite] == true
|
128
|
+
|
129
|
+
$stdout.sync = true
|
130
|
+
$stderr.sync = true
|
131
|
+
|
132
|
+
set_shell
|
133
|
+
|
134
|
+
@api_config.load_config
|
135
|
+
|
136
|
+
user_details = @tddium_api.user_logged_in?(true, params[:login])
|
137
|
+
if params[:login] && user_details.nil? then
|
138
|
+
exit_failure
|
139
|
+
end
|
140
|
+
|
141
|
+
if params[:repo] && !@scm.repo? then
|
142
|
+
say Text::Error::SCM_NOT_A_REPOSITORY
|
143
|
+
exit_failure
|
144
|
+
end
|
145
|
+
|
146
|
+
if params[:suite] && !suite_for_current_branch? then
|
147
|
+
exit_failure
|
148
|
+
end
|
149
|
+
|
150
|
+
@user_details = user_details
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Tddium
|
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 Tddium
|
4
|
+
module TimeFormat
|
5
|
+
extend Tddium::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 Tddium
|
4
|
+
class TddiumCli < 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.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,509 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module TddiumConstant
|
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']}/.tddium-server"
|
24
|
+
end
|
25
|
+
|
26
|
+
module Config
|
27
|
+
REMOTE_NAME = "tddium"
|
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
|
+
REPORT_TEST_EXECUTIONS = "#{TEST_EXECUTIONS}/report"
|
52
|
+
ACCOUNT_USAGE_BY_ACCOUNT = "accounts/usage_by_account"
|
53
|
+
MEMBERSHIPS = "memberships"
|
54
|
+
INSTANCES = "instances"
|
55
|
+
KEYS = "keys"
|
56
|
+
CONFIG = "env"
|
57
|
+
ACCOUNTS = "accounts"
|
58
|
+
REPOS = "repos"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module License
|
63
|
+
FILE_NAME = File.expand_path(File.join("..", "..", "..", "LICENSE.txt"), __FILE__)
|
64
|
+
end
|
65
|
+
|
66
|
+
module Text
|
67
|
+
module Prompt
|
68
|
+
module Response
|
69
|
+
YES = "y"
|
70
|
+
DISABLE = 'disable'
|
71
|
+
end
|
72
|
+
SSH_KEY = "Enter your ssh key or press 'Return'. Using '%s' by default:"
|
73
|
+
SUITE_NAME = "Enter a repo name or press 'Return'. Using '%s' by default:"
|
74
|
+
EMAIL = "Enter your email address: "
|
75
|
+
CURRENT_PASSWORD = "Enter your old password: "
|
76
|
+
PASSWORD = "Enter password: "
|
77
|
+
NEW_PASSWORD = "Enter a new password: "
|
78
|
+
PASSWORD_CONFIRMATION = "Confirm your password: "
|
79
|
+
INVITATION_TOKEN = "Enter your activation token:"
|
80
|
+
TEST_PATTERN = "Enter a pattern or press 'Return'. Using '%s' by default:"
|
81
|
+
CI_PULL_URL = "Enter git URL to pull from (default '%s') or enter 'disable':"
|
82
|
+
CI_PUSH_URL = "Enter git URL to push to (default '%s') or enter 'disable':"
|
83
|
+
CAMPFIRE_ROOM = "Custom Campfire room for this suite (current: '%s') or enter 'disable':"
|
84
|
+
HIPCHAT_ROOM = "Custom HipChat room for this suite (current: '%s') or enter 'disable':"
|
85
|
+
ACCOUNT = "Enter the organization to create the suite under:"
|
86
|
+
ACCOUNT_DEFAULT = "Enter the organization to create the suite under (default: '%s'):"
|
87
|
+
end
|
88
|
+
|
89
|
+
module Warning
|
90
|
+
USE_PASSWORD_TOKEN = "If you signed up with Github, use token from web dashboard as password"
|
91
|
+
HG_VERSION = "Unsupported hg version: %s"
|
92
|
+
HG_PATHS_DEFAULT_NOT_URI = "hg paths default not a URI"
|
93
|
+
HG_GIT_MIRROR_MISSING =<<EOF
|
94
|
+
|
95
|
+
* The hg <-> git mirror is missing.
|
96
|
+
|
97
|
+
Please run `tddium hg:mirror` to create the mirror for the first time.
|
98
|
+
|
99
|
+
(Note: it may take several minutes, or even an hour, for hg:mirror to complete,
|
100
|
+
depending on how large your repo is. Rest assured, you'll only need to run hg:mirror once.)
|
101
|
+
|
102
|
+
EOF
|
103
|
+
GIT_VERSION = "Unsupported git version: %s"
|
104
|
+
SCM_CHANGES_NOT_COMMITTED = "There are uncommitted changes in the local repository"
|
105
|
+
SCM_UNABLE_TO_DETECT = "Unable to detect uncommitted changes"
|
106
|
+
YAML_PARSE_FAILED = "Unable to parse %s as YAML"
|
107
|
+
TEST_CONFIGS_MUST_BE_LIST = "The test_configs section of solano.yml must be a list of configurations"
|
108
|
+
NO_SSH_KEY =<<EOF
|
109
|
+
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
|
110
|
+
EOF
|
111
|
+
end
|
112
|
+
|
113
|
+
module Process
|
114
|
+
SSH_KEY_NEEDED = "\nIt looks like you haven't authorized an SSH key to use with Solano CI.\n\n"
|
115
|
+
DEFAULT_KEY_ADDED = "SSH key authorized."
|
116
|
+
NO_KEYS = "No authorized keys."
|
117
|
+
ADD_KEYS_ADD = "Adding key '%s'"
|
118
|
+
ADD_KEYS_ADD_DONE =<<EOF
|
119
|
+
Authorized key '%s'.
|
120
|
+
|
121
|
+
Assuming your private key is in %s, you can just add the following
|
122
|
+
to ~/.ssh/config to use this new key with Solano CI:
|
123
|
+
|
124
|
+
# Solano CI SSH Config
|
125
|
+
Host %s
|
126
|
+
IdentityFile %s
|
127
|
+
IdentitiesOnly yes
|
128
|
+
EOF
|
129
|
+
ADD_KEYS_GENERATE = "Generating key '%s'"
|
130
|
+
ADD_KEYS_GENERATE_DONE =<<EOF
|
131
|
+
Generated and authorized key '%s'.
|
132
|
+
|
133
|
+
Append the following to ~/.ssh/config to use this new key with Solano CI:
|
134
|
+
|
135
|
+
# Solano CI SSH Config
|
136
|
+
Host %s
|
137
|
+
IdentityFile %s
|
138
|
+
IdentitiesOnly yes
|
139
|
+
EOF
|
140
|
+
REMOVE_KEYS = "Removing key '%s'"
|
141
|
+
REMOVE_KEYS_DONE = "Removed key '%s'"
|
142
|
+
|
143
|
+
NO_CONFIG = "No environment variables configured."
|
144
|
+
ADD_CONFIG = "Adding config %s=%s to %s"
|
145
|
+
ADD_CONFIG_DONE = "Added config %s=%s to %s"
|
146
|
+
REMOVE_CONFIG = "Removing config '%s' from %s"
|
147
|
+
REMOVE_CONFIG_DONE = "Removed config '%s' from %s"
|
148
|
+
CONFIG_EDIT_COMMANDS =<<EOF
|
149
|
+
|
150
|
+
Use `tddium config:add <scope> <key> <value>` to set a config key.
|
151
|
+
Use `tddium config:remove <scope> <key>` to remove a key.
|
152
|
+
|
153
|
+
EOF
|
154
|
+
KEYS_EDIT_COMMANDS =<<EOF
|
155
|
+
|
156
|
+
Use `tddium keys:add` to generate and authorize a new SSH keypair.
|
157
|
+
Use `tddium keys:remove` to remove an authorized key from Solano CI.
|
158
|
+
|
159
|
+
Use `ssh-keygen -lf <filename>` to print fingerprint of an existing public key.
|
160
|
+
|
161
|
+
EOF
|
162
|
+
TEST_PATTERN_INSTRUCTIONS =<<EOF
|
163
|
+
|
164
|
+
>>> Solano CI selects tests to run by default (e.g., in CI) by matching against a
|
165
|
+
list of Ruby glob patterns. Use "," to join multiple globs.
|
166
|
+
|
167
|
+
You can instead specify a list of test patterns in config/solano.yml.
|
168
|
+
|
169
|
+
Read more here: https://docs.solanolabs.com/
|
170
|
+
|
171
|
+
EOF
|
172
|
+
NO_CONFIGURED_SUITE = "Looks like you haven't configured Solano CI on this computer for %s/%s...\n"
|
173
|
+
FOUND_EXISTING_SUITE = "Found a suite in Solano CI for\n\n%s\n\n(on branch %s)."
|
174
|
+
TERMINATE_INSTRUCTION = ">>> Press Ctrl-C to stop waiting. Tests will continue running.\n"
|
175
|
+
INTERRUPT = "Interrupted"
|
176
|
+
SCM_PUSH = ">>> Pushing changes to Solano CI..."
|
177
|
+
SCM_REPO_WAIT = ">>> Waiting for your repository to be prepared. Sleeping for 10 seconds..."
|
178
|
+
STARTING_TEST = ">>> Starting Session with %s tests..."
|
179
|
+
CHECK_TEST_STATUS = ">>> Use 'tddium status' to check on pending jobs"
|
180
|
+
FINISHED_TEST = "Finished in %s seconds"
|
181
|
+
RUN_TDDIUM_WEB = "\n>>> Run `tddium web` to open the latest test results in your browser.\n"
|
182
|
+
CHECK_TEST_REPORT = ">>> To view results, visit: %s"
|
183
|
+
FAILED_TESTS = "Failed tests:"
|
184
|
+
SUMMARY_STATUS = "Final result: %s."
|
185
|
+
EXISTING_SUITE = "\nCurrent suite:\n"
|
186
|
+
USING_EXISTING_SUITE = "Using suite '%s/%s'."
|
187
|
+
CREATING_SUITE = "Creating suite '%s/%s'. This will take a few seconds."
|
188
|
+
CREATING_SUITE_CI_DISABLED = "Disabling automatic CI for this new branch."
|
189
|
+
CREATED_SUITE = "\nCreated suite.\n"
|
190
|
+
PASSWORD_CONFIRMATION_INCORRECT = "Password confirmation incorrect"
|
191
|
+
PASSWORD_CHANGED = "Your password has been changed."
|
192
|
+
NEXT_STEPS = "
|
193
|
+
|
194
|
+
Next, you should register your test suite and start tests by running:
|
195
|
+
|
196
|
+
$ tddium run
|
197
|
+
|
198
|
+
"
|
199
|
+
ALREADY_LOGGED_IN = "You're already logged in"
|
200
|
+
LOGGED_IN_SUCCESSFULLY = "Logged in successfully"
|
201
|
+
LOGGED_OUT_SUCCESSFULLY = "Logged out successfully"
|
202
|
+
USING_SPEC_OPTION = {:max_parallelism => "Max number of tests in parallel = %s",
|
203
|
+
:user_data_file => "Sending user data from %s",
|
204
|
+
:test_pattern => "Selecting tests that match '%s'",
|
205
|
+
:test_exclude_pattern => "Excluding tests that match '%s'"}
|
206
|
+
REMEMBERED = " (Remembered value)"
|
207
|
+
UPDATED_SUITE = "Updated suite successfully."
|
208
|
+
UPDATED_TEST_PATTERN = "Updated test pattern to '%s'"
|
209
|
+
UPDATED_TEST_EXCLUDE_PATTERN = "Updated test exclude pattern to '%s'"
|
210
|
+
UPDATED_RUBY_VERSION = "Updated ruby version to '%s'"
|
211
|
+
UPDATED_BUNDLER_VERSION = "Updated bundler version to '%s'"
|
212
|
+
UPDATED_PYTHON_CONFIG = "Updated Python configuration:\n%s"
|
213
|
+
UPDATED_TEST_CONFIGS = "Updated test configurations:\n%s"
|
214
|
+
DEPENDENCY_VERSION = "... Detected %s %s"
|
215
|
+
CONFIGURED_VERSION = "Configured %s %s from %s"
|
216
|
+
CONFIGURED_PATTERN =<<EOF;
|
217
|
+
... Configured test pattern from %s:
|
218
|
+
|
219
|
+
%s
|
220
|
+
|
221
|
+
>>> To change the pattern:
|
222
|
+
1. Edit %s
|
223
|
+
2. Run `tddium suite --edit` again.
|
224
|
+
EOF
|
225
|
+
CONFIGURED_EXCLUDE_PATTERN =<<EOF;
|
226
|
+
... Configured test exclude pattern from %s:
|
227
|
+
|
228
|
+
%s
|
229
|
+
|
230
|
+
>>> To change the pattern:
|
231
|
+
1. Edit %s
|
232
|
+
2. Run `tddium suite --edit` again.
|
233
|
+
EOF
|
234
|
+
DETECTED_BRANCH = "... Detected branch %s"
|
235
|
+
SETUP_CI=<<EOF;
|
236
|
+
|
237
|
+
>>> To set up Hosted CI, enter a git URL to pull from.
|
238
|
+
You can also set a git URL to push to after tests pass.
|
239
|
+
|
240
|
+
>>> Set both pull and push URLs to 'disable' to disable hosted CI completely.
|
241
|
+
|
242
|
+
EOF
|
243
|
+
SETUP_CAMPFIRE=<<EOF;
|
244
|
+
|
245
|
+
|
246
|
+
EOF
|
247
|
+
|
248
|
+
ADDING_MEMBER = "Adding %s as %s..."
|
249
|
+
ADDED_MEMBER = "Added %s"
|
250
|
+
REMOVING_MEMBER = "Removing %s. This may take a few seconds..."
|
251
|
+
REMOVED_MEMBER = "Removed %s"
|
252
|
+
|
253
|
+
USING_ACCOUNT_FROM_FLAG = "Using organization '%s' (from command line)."
|
254
|
+
USING_ACCOUNT = "Using organization '%s'."
|
255
|
+
|
256
|
+
CONFIRM_DELETE_SUITE = <<EOF.rstrip
|
257
|
+
Are you sure you want to delete the suite %s/%s
|
258
|
+
in organization %s?
|
259
|
+
This will delete all sessions associated with this suite, and cannot be un-done.
|
260
|
+
y/[n]:
|
261
|
+
EOF
|
262
|
+
SUITE_IN_MULTIPLE_ACCOUNTS = "The suite %s/%s exists in multiple organization:"
|
263
|
+
SUITE_IN_MULTIPLE_ACCOUNTS_PROMPT = "Which organization do you want to delete it from:"
|
264
|
+
|
265
|
+
ABORTING = "Aborting."
|
266
|
+
DESCRIBE_SESSION =<<EOF
|
267
|
+
|
268
|
+
Session %d%s
|
269
|
+
Showing %s tests
|
270
|
+
|
271
|
+
EOF
|
272
|
+
RERUN_SESSION =<<EOF
|
273
|
+
|
274
|
+
Re-run failures from a session with `tddium rerun <session_id>`.
|
275
|
+
Extract details of a session with `tddium describe <session_id>`.
|
276
|
+
|
277
|
+
EOF
|
278
|
+
OPTIONS_SAVED = 'Options have been successfully saved.'
|
279
|
+
NOT_SAVED_OPTIONS = 'There is no server information saved. Run `tddium server:set`.'
|
280
|
+
BUILD_CONTINUES = 'Session will continue running.'
|
281
|
+
end # Process
|
282
|
+
|
283
|
+
module Status
|
284
|
+
SPEC_WARNINGS = "\n\n>>> Solano CI Warnings:\n\n"
|
285
|
+
SPEC_ERRORS = "\n\n>>> Solano CI Errors:\n"
|
286
|
+
NO_SUITE = "You currently do not have any suites"
|
287
|
+
ALL_SUITES = "Suites:"
|
288
|
+
CURRENT_SUITE = "Current suite: %s"
|
289
|
+
CURRENT_SUITE_UNAVAILABLE = "Your current suite is unavailable"
|
290
|
+
NO_ACTIVE_SESSION = "There are no running sessions for this repo."
|
291
|
+
ACTIVE_SESSIONS = "Your active sessions for this repo%s:"
|
292
|
+
NO_INACTIVE_SESSION = "There are no recent sessions on this branch."
|
293
|
+
INACTIVE_SESSIONS = "Latest sessions on branch %s:"
|
294
|
+
SESSION_DETAIL = " %10.10s %s %s in %s, %s"
|
295
|
+
ATTRIBUTE_DETAIL = " %s: %s"
|
296
|
+
SEPARATOR = "====="
|
297
|
+
USING_SUITE = "\nUsing suite:\n"
|
298
|
+
USER_DETAILS =<<EOF;
|
299
|
+
|
300
|
+
Username: <%=user["email"]%>
|
301
|
+
User created: <%=user["created_at"]%>
|
302
|
+
EOF
|
303
|
+
ACCOUNT_DETAILS =<<EOF;
|
304
|
+
|
305
|
+
Organization: <%=acct["account"]%>
|
306
|
+
|
307
|
+
Role: <%=acct["account_role"]%>
|
308
|
+
Owner: <%=acct["account_owner"]%>
|
309
|
+
Plan: <%=acct["plan"]%>
|
310
|
+
<% if acct["trial_remaining"] && acct["trial_remaining"] > 0 %> Trial Period Remaining: <%=acct["trial_remaining"]%> days<% end %>
|
311
|
+
<% if acct["account_url"] %> Organization Management URL: <%=acct["account_url"]%><% end %>
|
312
|
+
<% if acct["heroku"] %> Heroku Account Linked: <%=acct["heroku_activation_done"]%><% end %>
|
313
|
+
<% if acct["third_party_pubkey"] %>
|
314
|
+
>>> Authorize the following SSH public key to allow Solano CI's test workers to
|
315
|
+
install gems from private git repos or communicate via SSH to your servers:
|
316
|
+
|
317
|
+
<%= acct["third_party_pubkey"] %>
|
318
|
+
|
319
|
+
<%end%>
|
320
|
+
EOF
|
321
|
+
USER_THIRD_PARTY_KEY_DETAILS =<<EOF;
|
322
|
+
<% if user["third_party_pubkey"] %>
|
323
|
+
>>> Authorize the following SSH public key to allow Solano CI's test workers to
|
324
|
+
install gems from private git repos or communicate via SSH to your servers:
|
325
|
+
|
326
|
+
<%= user["third_party_pubkey"] %>
|
327
|
+
<%end%>
|
328
|
+
EOF
|
329
|
+
|
330
|
+
SUITE_DETAILS =<<EOF;
|
331
|
+
Organization: <%=suite["account"]%>
|
332
|
+
Repo: <%=suite["repo_url"]%>
|
333
|
+
Scm: <%=suite["scm"]%>
|
334
|
+
Branch: <%=suite["branch"]%>
|
335
|
+
Default Test Pattern: <%=suite["test_pattern"]%>
|
336
|
+
Ruby Version: <%=suite["ruby_version"]%>
|
337
|
+
Rubygems Version: <%=suite["rubygems_version"]%>
|
338
|
+
Bundler Version: <%=suite["bundler_version"]%>
|
339
|
+
<% if suite["ci_enabled"] %>
|
340
|
+
Solano CI is enabled with the following parameters:
|
341
|
+
|
342
|
+
Pull URL: <%=suite["ci_pull_url"]%>
|
343
|
+
|
344
|
+
Notifications:
|
345
|
+
|
346
|
+
<%=suite["ci_notifications"]%>
|
347
|
+
|
348
|
+
<% if suite["ci_pull_url"] =~ /^git@github.com:(.*).git$/ %>
|
349
|
+
>>> Solano CI will pull from your Github repository.
|
350
|
+
|
351
|
+
Visit https://github.com/<%= $1 %>/admin/keys
|
352
|
+
then click "Add another deploy key" and copy and paste this key:
|
353
|
+
|
354
|
+
<%=suite["ci_ssh_pubkey"]%>
|
355
|
+
<% else %>
|
356
|
+
>>> Authorize the following SSH key to let Solano CI's pulls and pushes through:
|
357
|
+
|
358
|
+
<%=suite["ci_ssh_pubkey"]%>
|
359
|
+
<% end %><% if suite["ci_push_url"] =~ /^git@heroku.com:(.*).git$/ %>
|
360
|
+
>>> Solano CI will push to your Heroku application <%= $1 %>.
|
361
|
+
To authorize the key, use the following command:
|
362
|
+
|
363
|
+
heroku keys:add <%= tddium_deploy_key_file_name %> --app <%= $1 %>
|
364
|
+
<% end %><% if suite["ci_pull_url"] =~ /^git@github.com:(.*).git$/ %>
|
365
|
+
>>> Configure Github to notify Solano CI of your commits with a post-receive hook.
|
366
|
+
|
367
|
+
Visit https://github.com/<%= $1 %>/admin/hooks#generic_minibucket
|
368
|
+
then add the following URL and click "Update Settings":
|
369
|
+
<%=suite["hook_uri"]%>
|
370
|
+
<% else %>
|
371
|
+
>>> In order for Solano CI to know that your repo has changed, you'll need to
|
372
|
+
configure a post-commit hook in your Git server.
|
373
|
+
|
374
|
+
In Unix-based Git repositories, find the repository root and look for
|
375
|
+
a shell script in `.git/hooks/post-commit`.
|
376
|
+
|
377
|
+
To trigger CI builds, POST to the following URL from a post-commit hook:
|
378
|
+
<%=suite["hook_uri"]%>
|
379
|
+
<% end %>
|
380
|
+
|
381
|
+
>>> See http://docs.solanolabs.com/ for more information on Solano CI.
|
382
|
+
>>> You can enable Campfire and HipChat notifications from your Solano CI Dashboard.
|
383
|
+
<% end %>
|
384
|
+
>>> Run 'tddium suite --edit' to edit these settings.
|
385
|
+
>>> Run 'tddium spec' to run tests in this suite.
|
386
|
+
EOF
|
387
|
+
ACCOUNT_MEMBERS = "Authorized users:"
|
388
|
+
KEYS_DETAILS =<<EOF
|
389
|
+
|
390
|
+
You have authorized the following SSH public keys to communicate with Solano CI:
|
391
|
+
|
392
|
+
Name Fingerprint
|
393
|
+
------------------ ------------------------------------------------------------
|
394
|
+
EOF
|
395
|
+
CONFIG_DETAILS =<<EOF
|
396
|
+
The following environment variables are set for this %s:
|
397
|
+
|
398
|
+
EOF
|
399
|
+
SESSION_STATUS =<<EOF
|
400
|
+
|
401
|
+
Session Details:
|
402
|
+
|
403
|
+
Commit: %s (%s)
|
404
|
+
Status: %s
|
405
|
+
Finished: %s
|
406
|
+
|
407
|
+
EOF
|
408
|
+
end
|
409
|
+
|
410
|
+
module Error
|
411
|
+
OPTIONS_NOT_SAVED = 'Options have not been saved.'
|
412
|
+
KEY_ALREADY_EXISTS = "Aborting. SSH key already exists: %s"
|
413
|
+
KEYGEN_FAILED = "Failed to generate new SSH key for '%s'"
|
414
|
+
LIST_KEYS_ERROR = "Error listing SSH keys"
|
415
|
+
REMOVE_KEYS_ERROR = "Failed to remove key '%s'"
|
416
|
+
ADD_KEYS_DUPLICATE = "You already have a key named '%s'"
|
417
|
+
ADD_KEY_CONTENT_DUPLICATE = "You already have a key named '%s' with the same content"
|
418
|
+
ADD_KEYS_ERROR = "Failed to add key '%s'"
|
419
|
+
LIST_CONFIG_ERROR = "Error listing configuration variables"
|
420
|
+
ADD_CONFIG_ERROR = "Error setting configuration variable"
|
421
|
+
REMOVE_CONFIG_ERROR = "Error removing configuration variable"
|
422
|
+
SCM_NOT_A_REPOSITORY = "Current working directory is not a suitable repository"
|
423
|
+
INVALID_CONFIGURED_PATTERN =<<EOF;
|
424
|
+
Configuring test pattern from %s...
|
425
|
+
|
426
|
+
>>> The test_pattern in %s is not properly formatted. It must be a YAML list.
|
427
|
+
|
428
|
+
You entered:
|
429
|
+
|
430
|
+
%s
|
431
|
+
|
432
|
+
>>> Edit %s and rerun `tddium suite --edit`
|
433
|
+
|
434
|
+
EOF
|
435
|
+
SCM_REPO_NOT_READY = "Your repository is being prepped. Try again in a minute."
|
436
|
+
SCM_PUSH_FAILED = <<EOF;
|
437
|
+
|
438
|
+
Attempt to push source to Solano CI failed.
|
439
|
+
|
440
|
+
If you get a "Permission denied (publickey)" message, ensure that SSH is
|
441
|
+
configured to send a key you have authorized with Solano CI (Run `tddium keys` to
|
442
|
+
see a list.)
|
443
|
+
|
444
|
+
For any other error, contact us at: support@solanolabs.com
|
445
|
+
|
446
|
+
|
447
|
+
EOF
|
448
|
+
INVALID_SSH_PUBLIC_KEY = '%s does not appear to be a valid SSH public key'
|
449
|
+
INACCESSIBLE_SSH_PUBLIC_KEY = '%s is not accessible: %s'
|
450
|
+
SCM_CHANGES_NOT_COMMITTED =<<EOF
|
451
|
+
There are uncommitted changes in the local repository.
|
452
|
+
|
453
|
+
Commit changes before running 'tddium spec'.
|
454
|
+
|
455
|
+
Use 'tddium spec --force' to test with only already-committed changes.
|
456
|
+
EOF
|
457
|
+
NOT_INITIALIZED = "Solano CI must be initialized. Try 'tddium login'"
|
458
|
+
INVALID_TDDIUM_FILE = ".tddium.%s config file is corrupt. Try 'tddium login'"
|
459
|
+
SCM_NOT_FOUND = "Solano CI requires git or mercurial which are not on your PATH"
|
460
|
+
SCM_NOT_INITIALIZED =<<EOF;
|
461
|
+
It doesn't look like you're in a git repo. If you're not, use 'git init' to
|
462
|
+
create one.
|
463
|
+
|
464
|
+
If you are in a git repo and you're still seeing this message,
|
465
|
+
you may be using an unsupported version of git.
|
466
|
+
|
467
|
+
Please email us at support@solanolabs.com with the following trace information:
|
468
|
+
|
469
|
+
>>>>>>>>>>>>> BEGIN GIT TRACE >>>>>>>>>>>>>>>>>>>>>>>>>
|
470
|
+
hg version: #{`hg status 2> /dev/null && hg -q --version 2>&1`}
|
471
|
+
git version: #{`git status 2> /dev/null && git --version 2>&1`}
|
472
|
+
git status: #{`git status 2> /dev/null && git status 2>&1`}
|
473
|
+
git status result: #{ $? }
|
474
|
+
git details: #{`git status 2> /dev/null && git status --porcelain 2>&1`}
|
475
|
+
git details result: #{ $? }
|
476
|
+
>>>>>>>>>>>>> END GIT TRACE >>>>>>>>>>>>>>>>>>>>>>>>>
|
477
|
+
EOF
|
478
|
+
NO_SESSION_EXISTS = "No session exists for the current branch. Use 'tddium run'"
|
479
|
+
NO_SUITE_EXISTS = "No suite exists for the branch '%s'. Try running 'tddium suite'"
|
480
|
+
TRY_DEFAULT_BRANCH = "Getting suites for default '%s' branch."
|
481
|
+
NO_USER_DATA_FILE = "User data file '%s' does not exist"
|
482
|
+
NO_MATCHING_FILES = "No files match '%s'"
|
483
|
+
PASSWORD_ERROR = "Error changing password: %s"
|
484
|
+
ADD_MEMBER_ERROR = "Error adding %s: %s"
|
485
|
+
REMOVE_MEMBER_ERROR = "Error removing %s: %s"
|
486
|
+
USE_ACTIVATE = "Visit 'https://ci.solanolabs.com' to activate your account for the first time."
|
487
|
+
INVALID_CREDENTIALS = "Your .tddium file has an invalid API key.\nRun `tddium logout` and `tddium login`, and then try again."
|
488
|
+
MISSING_ACCOUNT_OPTION = "You must specify an organization by passing the --org option."
|
489
|
+
MISSING_ACCOUNT = "You must specify an organization."
|
490
|
+
NOT_IN_ACCOUNT = "You aren't a member of organization %s."
|
491
|
+
CANT_FIND_SUITE = "Can't find suite for %s/%s"
|
492
|
+
INVALID_ACCOUNT_NAME = "Invalid organization name."
|
493
|
+
CANT_INVOKE_COMMAND =<<EOF
|
494
|
+
ERROR: could not invoke tddium command
|
495
|
+
Usage: "tddium COMMAND [ARGS] [OPTIONS]". For available commands, run "tddium help".
|
496
|
+
EOF
|
497
|
+
CONFIG_PATHS_COLLISION =<<EOF
|
498
|
+
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 tddium.yml file will soon be deprecated, so we recommend migrating all of your configuration to solano.yml.
|
499
|
+
EOF
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
module DisplayedAttributes
|
504
|
+
SUITE = %w{repo_url branch test_pattern
|
505
|
+
ruby_version bundler_version rubygems_version
|
506
|
+
test_scripts test_executions git_repo_uri}
|
507
|
+
TEST_EXECUTION = %w{start_time end_time test_execution_stats report}
|
508
|
+
end
|
509
|
+
end
|