tddium 1.25.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
data/lib/tddium/scm.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Tddium
|
4
|
+
class Git
|
5
|
+
include TddiumConstant
|
6
|
+
|
7
|
+
def scm_name
|
8
|
+
return 'git'
|
9
|
+
end
|
10
|
+
|
11
|
+
def repo?
|
12
|
+
if File.directory?('.git') then
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
ignore = `git status 2>&1`
|
16
|
+
ok = $?.success?
|
17
|
+
return ok
|
18
|
+
end
|
19
|
+
|
20
|
+
def root
|
21
|
+
root = `git rev-parse --show-toplevel 2>&1`
|
22
|
+
if $?.exitstatus == 0 then
|
23
|
+
root.chomp! if root
|
24
|
+
return root
|
25
|
+
end
|
26
|
+
return Dir.pwd
|
27
|
+
end
|
28
|
+
|
29
|
+
def mirror_path
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def repo_name
|
34
|
+
return File.basename(self.root)
|
35
|
+
end
|
36
|
+
|
37
|
+
def origin_url
|
38
|
+
result = `(git config --get remote.origin.url || echo GIT_FAILED) 2>/dev/null`
|
39
|
+
return nil if result =~ /GIT_FAILED/
|
40
|
+
result.strip
|
41
|
+
end
|
42
|
+
|
43
|
+
def ignore_path
|
44
|
+
path = File.join(self.root, Config::GIT_IGNORE)
|
45
|
+
return path
|
46
|
+
end
|
47
|
+
|
48
|
+
def current_branch
|
49
|
+
`git symbolic-ref HEAD`.gsub("\n", "").split("/")[2..-1].join("/")
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_branch
|
53
|
+
`git remote show origin | grep HEAD | awk '{print $3}'`.gsub("\n", "")
|
54
|
+
end
|
55
|
+
|
56
|
+
# XXX DANGER: This method will edit the current workspace. It's meant to
|
57
|
+
# be run to make a git mirror up-to-date.
|
58
|
+
def checkout(branch, options={})
|
59
|
+
if !!options[:update] then
|
60
|
+
`git fetch origin`
|
61
|
+
return false if !$?.success?
|
62
|
+
end
|
63
|
+
|
64
|
+
cmd = "git checkout "
|
65
|
+
if !!options[:force] then
|
66
|
+
cmd += "-f "
|
67
|
+
end
|
68
|
+
cmd += Shellwords.shellescape(branch)
|
69
|
+
`#{cmd}`
|
70
|
+
|
71
|
+
return false if !$?.success?
|
72
|
+
|
73
|
+
`git reset --hard origin/#{branch}`
|
74
|
+
return $?.success?
|
75
|
+
end
|
76
|
+
|
77
|
+
def changes?(options={})
|
78
|
+
return Tddium::Git.git_changes?(:exclude=>".gitignore")
|
79
|
+
end
|
80
|
+
|
81
|
+
def push_latest(session_data, suite_details, options={})
|
82
|
+
branch = options[:branch] || self.current_branch
|
83
|
+
remote_branch = options[:remote_branch] || branch
|
84
|
+
git_repo_uri = if options[:git_repo_uri] then
|
85
|
+
options[:git_repo_uri]
|
86
|
+
elsif options[:use_private_uri] then
|
87
|
+
suite_details["git_repo_private_uri"] || suite_details["git_repo_uri"]
|
88
|
+
else
|
89
|
+
suite_details["git_repo_uri"]
|
90
|
+
end
|
91
|
+
this_ref = (session_data['commit_data'] || {})['git_ref']
|
92
|
+
refs = this_ref ? ["HEAD:#{this_ref}"] : []
|
93
|
+
|
94
|
+
if options[:git_repo_origin_uri] then
|
95
|
+
Tddium::Git.git_set_remotes(options[:git_repo_origin_uri], 'origin')
|
96
|
+
end
|
97
|
+
|
98
|
+
Tddium::Git.git_set_remotes(git_repo_uri)
|
99
|
+
return Tddium::Git.git_push(branch, refs, remote_branch)
|
100
|
+
end
|
101
|
+
|
102
|
+
def current_commit
|
103
|
+
`git rev-parse --verify HEAD`.strip
|
104
|
+
end
|
105
|
+
|
106
|
+
def commits
|
107
|
+
commits = GitCommitLogParser.new(self.latest_commit).commits
|
108
|
+
return commits
|
109
|
+
end
|
110
|
+
|
111
|
+
def number_of_commits(id_from, id_to)
|
112
|
+
result = `git log --pretty='%H' #{id_from}..#{id_to}`
|
113
|
+
result.split("\n").length
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
def latest_commit
|
119
|
+
`git log --pretty='%H%n%s%n%aN%n%aE%n%at%n%cN%n%cE%n%ct%n' HEAD^..HEAD`
|
120
|
+
end
|
121
|
+
|
122
|
+
class << self
|
123
|
+
include TddiumConstant
|
124
|
+
|
125
|
+
def git_changes?(options={})
|
126
|
+
options[:exclude] ||= []
|
127
|
+
options[:exclude] = [options[:exclude]] unless options[:exclude].is_a?(Array)
|
128
|
+
cmd = "(git status --porcelain -uno || echo GIT_FAILED) < /dev/null 2>&1"
|
129
|
+
p = IO.popen(cmd)
|
130
|
+
changes = false
|
131
|
+
while line = p.gets do
|
132
|
+
if line =~ /GIT_FAILED/
|
133
|
+
warn(Text::Warning::SCM_UNABLE_TO_DETECT)
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
line = line.strip
|
137
|
+
status, name = line.split(/\s+/)
|
138
|
+
next if options[:exclude].include?(name)
|
139
|
+
if status !~ /^\?/ then
|
140
|
+
changes = true
|
141
|
+
break
|
142
|
+
end
|
143
|
+
end
|
144
|
+
return changes
|
145
|
+
end
|
146
|
+
|
147
|
+
def git_set_remotes(git_repo_uri, remote_name=nil)
|
148
|
+
remote_name ||= Config::REMOTE_NAME
|
149
|
+
|
150
|
+
unless `git remote show -n #{remote_name}` =~ /#{git_repo_uri}/
|
151
|
+
`git remote rm #{remote_name} > /dev/null 2>&1`
|
152
|
+
`git remote add #{remote_name} #{git_repo_uri.shellescape}`
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def git_push(this_branch, additional_refs=[], remote_branch=nil)
|
157
|
+
say Text::Process::SCM_PUSH
|
158
|
+
remote_branch ||= this_branch
|
159
|
+
refs = ["#{this_branch}:#{remote_branch}"]
|
160
|
+
refs += additional_refs
|
161
|
+
refspec = refs.map(&:shellescape).join(" ")
|
162
|
+
cmd = "git push -f #{Config::REMOTE_NAME} #{refspec}"
|
163
|
+
say "Running '#{cmd}'"
|
164
|
+
system(cmd)
|
165
|
+
end
|
166
|
+
|
167
|
+
def version_ok
|
168
|
+
version = nil
|
169
|
+
begin
|
170
|
+
version_string = `git --version`
|
171
|
+
m = version_string.match(Dependency::VERSION_REGEXP)
|
172
|
+
version = m[0] unless m.nil?
|
173
|
+
rescue Errno
|
174
|
+
rescue Exception
|
175
|
+
end
|
176
|
+
if version.nil? || version.empty? then
|
177
|
+
abort Text::Error::SCM_NOT_FOUND
|
178
|
+
end
|
179
|
+
version_parts = version.split(".")
|
180
|
+
if version_parts[0].to_i < 1 ||
|
181
|
+
(version_parts[0].to_i < 2 && version_parts[1].to_i == 1 && version_parts[1].to_i < 7) then
|
182
|
+
warn(Text::Warning::GIT_VERSION % version)
|
183
|
+
end
|
184
|
+
true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
# this is not namespaced under Tddium because we want to eventually move this out into another gem
|
4
|
+
class GitCommitLogParser
|
5
|
+
attr_accessor :commit_log
|
6
|
+
|
7
|
+
# example commit_log generated by
|
8
|
+
# `git log --pretty='%H%n%s%n%aN%n%aE%n%at%n%cN%n%cE%n%ct%n' HEAD^..HEAD`
|
9
|
+
|
10
|
+
# 15e8cbd88d68d210953d51c28e26c6b9944a313b
|
11
|
+
# ignore .ruby-version for rvm
|
12
|
+
# Bob Smith
|
13
|
+
# bob@example.com
|
14
|
+
# 1367556311
|
15
|
+
# Fred Smith
|
16
|
+
# fred@example.com
|
17
|
+
# 1367556311
|
18
|
+
#
|
19
|
+
|
20
|
+
def initialize(commit_log)
|
21
|
+
@commit_log = commit_log
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a list of commits in the following format
|
25
|
+
# [{
|
26
|
+
# "id" => "15e8cbd88d68d210953d51c28e26c6b9944a313b",
|
27
|
+
# "author" => {"name"=>"Bob Smith", "email"=>"bob@example.com"},
|
28
|
+
# "committer" => {"name"=>"Fred Smith", "email"=>"fred@example.com"},
|
29
|
+
# "summary" => "ignore .ruby-version for rvm",
|
30
|
+
# "date" => 1380603292
|
31
|
+
# }]
|
32
|
+
|
33
|
+
def commits
|
34
|
+
record = []
|
35
|
+
commits = []
|
36
|
+
commit_log.lines.each do |line|
|
37
|
+
line.strip!
|
38
|
+
line.sanitize!
|
39
|
+
if line.empty?
|
40
|
+
c = parse_commit(record)
|
41
|
+
commits.push(c)
|
42
|
+
record = []
|
43
|
+
else
|
44
|
+
record.push(line)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
commits
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def parse_commit(record)
|
54
|
+
time = record[4].to_i
|
55
|
+
author = build_user(record[2], record[3])
|
56
|
+
committer = build_user(record[5], record[6])
|
57
|
+
build_commit(record[0], author, committer, record[1], time)
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_user(name, email)
|
61
|
+
{"name" => name, "email" => email}
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_commit(sha, author, committer, summary, date)
|
65
|
+
{"id" => sha, "author" => author, "committer" => committer, "summary" => summary, "date" => date}
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'shellwords'
|
5
|
+
|
6
|
+
module Tddium
|
7
|
+
class Hg
|
8
|
+
include TddiumConstant
|
9
|
+
|
10
|
+
def scm_name
|
11
|
+
return 'hg'
|
12
|
+
end
|
13
|
+
|
14
|
+
def repo?
|
15
|
+
if File.directory?('.hg') then
|
16
|
+
return true
|
17
|
+
end
|
18
|
+
ignore = `hg status 2>&1`
|
19
|
+
ok = $?.success?
|
20
|
+
return ok
|
21
|
+
end
|
22
|
+
|
23
|
+
def root
|
24
|
+
root = `hg root`
|
25
|
+
if $?.exitstatus == 0 then
|
26
|
+
root.chomp! if root
|
27
|
+
return root
|
28
|
+
end
|
29
|
+
return Dir.pwd
|
30
|
+
end
|
31
|
+
|
32
|
+
def repo_name
|
33
|
+
return File.basename(self.root)
|
34
|
+
end
|
35
|
+
|
36
|
+
def origin_url
|
37
|
+
result = `(hg paths default || echo HG_FAILED) 2>/dev/null`
|
38
|
+
return nil if result =~ /HG_FAILED/
|
39
|
+
result.strip!
|
40
|
+
u = URI.parse(result) rescue nil
|
41
|
+
if u && u.host.nil? then
|
42
|
+
warn(Text::Warning::HG_PATHS_DEFAULT_NOT_URI)
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
|
48
|
+
def ignore_path
|
49
|
+
path = File.join(self.root, Config::HG_IGNORE)
|
50
|
+
return path
|
51
|
+
end
|
52
|
+
|
53
|
+
def current_branch
|
54
|
+
branch = `hg branch`
|
55
|
+
branch.chomp!
|
56
|
+
return branch
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_branch
|
60
|
+
# NOTE: not necessarily quite right in HG 2.1+ with a default bookmark
|
61
|
+
return "default"
|
62
|
+
end
|
63
|
+
|
64
|
+
def changes?(options={})
|
65
|
+
return Tddium::Hg.hg_changes?(:exclude=>".hgignore")
|
66
|
+
end
|
67
|
+
|
68
|
+
def hg_push(uri)
|
69
|
+
cmd = "hg push -f -b #{self.current_branch} "
|
70
|
+
cmd += " #{uri}"
|
71
|
+
|
72
|
+
# git outputs something to stderr when it runs git push.
|
73
|
+
# hg doesn't always ... so show the command that's being run and its
|
74
|
+
# output to indicate progress.
|
75
|
+
puts cmd
|
76
|
+
puts `#{cmd}`
|
77
|
+
return [0,1].include?( $?.exitstatus )
|
78
|
+
end
|
79
|
+
|
80
|
+
def push_latest(session_data, suite_details, options={})
|
81
|
+
uri = if options[:use_private_uri] then
|
82
|
+
suite_details["git_repo_private_uri"] || suite_details["git_repo_uri"]
|
83
|
+
else
|
84
|
+
suite_details["git_repo_uri"]
|
85
|
+
end
|
86
|
+
self.hg_push(uri)
|
87
|
+
end
|
88
|
+
|
89
|
+
def current_commit
|
90
|
+
commit = `hg id -i`
|
91
|
+
commit.chomp!
|
92
|
+
return commit
|
93
|
+
end
|
94
|
+
|
95
|
+
def commits
|
96
|
+
commits = HgCommitLogParser.new(self.latest_commit).commits
|
97
|
+
return commits
|
98
|
+
end
|
99
|
+
|
100
|
+
def number_of_commits(id_from, id_to)
|
101
|
+
result = `hg log --template='{node}\\n' #{id_from}..#{id_to}`
|
102
|
+
result.split("\n").length
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def latest_commit
|
108
|
+
`hg log -f -l 1 --template='{node}\\n{desc|firstline}\\n{author|user}\\n{author|email}\\n{date}\\n{author|user}\\n{author|email}\\n{date}\\n\\n'`
|
109
|
+
end
|
110
|
+
|
111
|
+
class << self
|
112
|
+
include TddiumConstant
|
113
|
+
|
114
|
+
def hg_changes?(options={})
|
115
|
+
options[:exclude] ||= []
|
116
|
+
options[:exclude] = [options[:exclude]] unless options[:exclude].is_a?(Array)
|
117
|
+
cmd = "(hg status -mardu || echo HG_FAILED) < /dev/null 2>&1"
|
118
|
+
p = IO.popen(cmd)
|
119
|
+
changes = false
|
120
|
+
while line = p.gets do
|
121
|
+
if line =~ /HG_FAILED/
|
122
|
+
warn(Text::Warning::SCM_UNABLE_TO_DETECT)
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
line = line.strip
|
126
|
+
status, name = line.split(/\s+/)
|
127
|
+
next if options[:exclude].include?(name)
|
128
|
+
if status !~ /^\?/ then
|
129
|
+
changes = true
|
130
|
+
break
|
131
|
+
end
|
132
|
+
end
|
133
|
+
return changes
|
134
|
+
end
|
135
|
+
|
136
|
+
def hg_push(this_branch, additional_refs=[])
|
137
|
+
raise "not implemented"
|
138
|
+
end
|
139
|
+
|
140
|
+
def version_ok
|
141
|
+
version = nil
|
142
|
+
begin
|
143
|
+
version_string = `hg -q --version`
|
144
|
+
m = version_string.match(Dependency::VERSION_REGEXP)
|
145
|
+
version = m[0] unless m.nil?
|
146
|
+
rescue Errno
|
147
|
+
rescue Exception
|
148
|
+
end
|
149
|
+
if version.nil? || version.empty? then
|
150
|
+
abort Text::Error::SCM_NOT_FOUND
|
151
|
+
end
|
152
|
+
version_parts = version.split(".")
|
153
|
+
if version_parts[0].to_i < 2 then
|
154
|
+
warn(Text::Warning::HG_VERSION % version)
|
155
|
+
end
|
156
|
+
true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
# this is not namespaced under Tddium because we want to eventually move this out into another gem
|
4
|
+
class HgCommitLogParser
|
5
|
+
attr_accessor :commit_log
|
6
|
+
|
7
|
+
# example commit_log generated by
|
8
|
+
# `hg log -f -l 1 --template='{node}\n{desc|firstline}\n{author|user}\n{author|email}\n{date}\n{author|user}\n{author|email}\n{date}\n'`
|
9
|
+
|
10
|
+
# beb3d918995bbe6370bb21fd76b4f433bfd64dc4
|
11
|
+
# commit summary
|
12
|
+
# user
|
13
|
+
# user@host.domain
|
14
|
+
# 1399437808.00
|
15
|
+
# user
|
16
|
+
# user@host.domain
|
17
|
+
# 1399437808.00
|
18
|
+
|
19
|
+
def initialize(commit_log)
|
20
|
+
@commit_log = commit_log
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a list of commits in the following format
|
24
|
+
# [{
|
25
|
+
# "id" => "15e8cbd88d68d210953d51c28e26c6b9944a313b",
|
26
|
+
# "author" => {"name"=>"Bob Smith", "email"=>"bob@example.com"},
|
27
|
+
# "committer" => {"name"=>"Fred Smith", "email"=>"fred@example.com"},
|
28
|
+
# "summary" => "ignore .ruby-version for rvm",
|
29
|
+
# "date" => 1380603292
|
30
|
+
# }]
|
31
|
+
|
32
|
+
def commits
|
33
|
+
record = []
|
34
|
+
commits = []
|
35
|
+
commit_log.lines.each do |line|
|
36
|
+
line.strip!
|
37
|
+
line.sanitize!
|
38
|
+
if line.empty?
|
39
|
+
c = parse_commit(record)
|
40
|
+
commits.push(c)
|
41
|
+
record = []
|
42
|
+
else
|
43
|
+
record.push(line)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
commits
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def parse_commit(record)
|
53
|
+
time = record[4].to_i
|
54
|
+
author = build_user(record[2], record[3])
|
55
|
+
committer = build_user(record[5], record[6])
|
56
|
+
build_commit(record[0], author, committer, record[1], time)
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_user(name, email)
|
60
|
+
{"name" => name, "email" => email}
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_commit(sha, author, committer, summary, date)
|
64
|
+
{"id" => sha, "author" => author, "committer" => committer, "summary" => summary, "date" => date}
|
65
|
+
end
|
66
|
+
end
|