solano 1.31.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/solano +29 -0
- data/bin/tddium +29 -0
- data/lib/solano.rb +19 -0
- data/lib/solano/agent.rb +3 -0
- data/lib/solano/agent/solano.rb +128 -0
- data/lib/solano/cli.rb +25 -0
- data/lib/solano/cli/api.rb +368 -0
- data/lib/solano/cli/commands/account.rb +50 -0
- data/lib/solano/cli/commands/activate.rb +16 -0
- data/lib/solano/cli/commands/api.rb +15 -0
- data/lib/solano/cli/commands/config.rb +78 -0
- data/lib/solano/cli/commands/console.rb +85 -0
- data/lib/solano/cli/commands/describe.rb +104 -0
- data/lib/solano/cli/commands/find_failing.rb +64 -0
- data/lib/solano/cli/commands/heroku.rb +17 -0
- data/lib/solano/cli/commands/hg.rb +48 -0
- data/lib/solano/cli/commands/keys.rb +81 -0
- data/lib/solano/cli/commands/login.rb +37 -0
- data/lib/solano/cli/commands/logout.rb +14 -0
- data/lib/solano/cli/commands/password.rb +26 -0
- data/lib/solano/cli/commands/rerun.rb +59 -0
- data/lib/solano/cli/commands/server.rb +21 -0
- data/lib/solano/cli/commands/spec.rb +401 -0
- data/lib/solano/cli/commands/status.rb +117 -0
- data/lib/solano/cli/commands/stop.rb +19 -0
- data/lib/solano/cli/commands/suite.rb +110 -0
- data/lib/solano/cli/commands/support.rb +24 -0
- data/lib/solano/cli/commands/web.rb +29 -0
- data/lib/solano/cli/config.rb +246 -0
- data/lib/solano/cli/params_helper.rb +66 -0
- data/lib/solano/cli/prompt.rb +128 -0
- data/lib/solano/cli/show.rb +136 -0
- data/lib/solano/cli/solano.rb +208 -0
- data/lib/solano/cli/suite.rb +104 -0
- data/lib/solano/cli/text_helper.rb +16 -0
- data/lib/solano/cli/timeformat.rb +21 -0
- data/lib/solano/cli/util.rb +132 -0
- data/lib/solano/constant.rb +581 -0
- data/lib/solano/scm.rb +18 -0
- data/lib/solano/scm/configure.rb +37 -0
- data/lib/solano/scm/git.rb +349 -0
- data/lib/solano/scm/git_log_parser.rb +67 -0
- data/lib/solano/scm/hg.rb +263 -0
- data/lib/solano/scm/hg_log_parser.rb +66 -0
- data/lib/solano/scm/scm.rb +119 -0
- data/lib/solano/scm/scm_stub.rb +9 -0
- data/lib/solano/scm/url.rb +75 -0
- data/lib/solano/script.rb +12 -0
- data/lib/solano/script/git-remote-hg +1258 -0
- data/lib/solano/ssh.rb +66 -0
- data/lib/solano/util.rb +63 -0
- data/lib/solano/version.rb +5 -0
- metadata +413 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (c) 2011, 2012, 2013, 2014, 2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "account [--org NAME]", "View account information"
|
6
|
+
method_option :org, type: :string
|
7
|
+
def account
|
8
|
+
user_details = solano_setup({:scm => false})
|
9
|
+
|
10
|
+
if user_details then
|
11
|
+
# User is already logged in, so just display the info
|
12
|
+
show_user_details(user_details)
|
13
|
+
else
|
14
|
+
exit_failure Text::Error::USE_ACTIVATE
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "account:add [ROLE] [EMAIL]", "Authorize and invite a user to use your organization"
|
19
|
+
define_method "account:add" do |role, email|
|
20
|
+
solano_setup({:scm => false})
|
21
|
+
|
22
|
+
r = Regexp.new(/\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/)
|
23
|
+
if r !~ email then
|
24
|
+
exit_failure Text::Error::ADD_MEMBER_ERROR % [email, "Not a valid e-mail address: must be of the form user@host.domain"]
|
25
|
+
end
|
26
|
+
|
27
|
+
params = {:role=>role, :email=>email}
|
28
|
+
begin
|
29
|
+
say Text::Process::ADDING_MEMBER % [params[:email], params[:role]]
|
30
|
+
result = @solano_api.set_memberships(params)
|
31
|
+
say Text::Process::ADDED_MEMBER % email
|
32
|
+
rescue TddiumClient::Error::API => e
|
33
|
+
exit_failure Text::Error::ADD_MEMBER_ERROR % [email, e.message]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "account:remove [EMAIL]", "Remove a user from an organization"
|
38
|
+
define_method "account:remove" do |email|
|
39
|
+
solano_setup({:scm => false})
|
40
|
+
|
41
|
+
begin
|
42
|
+
say Text::Process::REMOVING_MEMBER % email
|
43
|
+
result = @solano_api.delete_memberships(email)
|
44
|
+
say Text::Process::REMOVED_MEMBER % email
|
45
|
+
rescue TddiumClient::Error::API => e
|
46
|
+
exit_failure Text::Error::REMOVE_MEMBER_ERROR % [email, e.message]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "activate", "Activate an account (deprecated)"
|
6
|
+
method_option :email, :type => :string, :default => nil
|
7
|
+
method_option :password, :type => :string, :default => nil
|
8
|
+
method_option :ssh_key_file, :type => :string, :default => nil
|
9
|
+
def activate
|
10
|
+
say "To activate your account, please visit"
|
11
|
+
say "https://ci.solanolabs.com/"
|
12
|
+
|
13
|
+
solano_setup({:scm => false})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "api:key", "Display Solano CI API Key"
|
6
|
+
define_method "api:key" do
|
7
|
+
user_details = solano_setup({:scm => false})
|
8
|
+
api_key = user_details['api_key']
|
9
|
+
if api_key.nil? then
|
10
|
+
exit_failure LIST_API_KEY_ERROR
|
11
|
+
end
|
12
|
+
say api_key
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "config [suite | repo | org] [--org NAME]", "Display config variables.
|
6
|
+
The scope argument can be 'suite', 'repo', 'org'. The default is 'suite'."
|
7
|
+
method_option :account, :type => :string, :default => nil,
|
8
|
+
:aliases => %w(--org --organization)
|
9
|
+
def config(scope="suite")
|
10
|
+
params = {:repo => true}
|
11
|
+
if scope == 'suite' then
|
12
|
+
params[:suite] = true
|
13
|
+
end
|
14
|
+
if options[:account] then
|
15
|
+
params[:account] = options[:account]
|
16
|
+
end
|
17
|
+
solano_setup(params)
|
18
|
+
|
19
|
+
begin
|
20
|
+
config_details = @solano_api.get_config_key(scope)
|
21
|
+
show_config_details(scope, config_details['env'])
|
22
|
+
rescue TddiumClient::Error::API => e
|
23
|
+
exit_failure Text::Error::LIST_CONFIG_ERROR
|
24
|
+
rescue Exception => e
|
25
|
+
exit_failure e.message
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "config:add [SCOPE] [KEY] [VALUE] [--org NAME]", "Set KEY=VALUE at SCOPE.
|
30
|
+
The scope argument can be 'suite', 'repo', 'org'."
|
31
|
+
method_option :account, :type => :string, :default => nil,
|
32
|
+
:aliases => %w(--org --organization)
|
33
|
+
define_method "config:add" do |scope, key, value|
|
34
|
+
params = {:repo => true}
|
35
|
+
if scope == 'suite' then
|
36
|
+
params[:suite] = true
|
37
|
+
end
|
38
|
+
if options[:account] then
|
39
|
+
params[:account] = options[:account]
|
40
|
+
end
|
41
|
+
solano_setup(params)
|
42
|
+
|
43
|
+
begin
|
44
|
+
say Text::Process::ADD_CONFIG % [key, value, scope]
|
45
|
+
result = @solano_api.set_config_key(scope, key, value)
|
46
|
+
say Text::Process::ADD_CONFIG_DONE % [key, value, scope]
|
47
|
+
rescue TddiumClient::Error::API => e
|
48
|
+
exit_failure Text::Error::ADD_CONFIG_ERROR
|
49
|
+
rescue Exception => e
|
50
|
+
exit_failure e.message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "config:remove [SCOPE] [KEY] [--org NAME]", "Remove config variable NAME from SCOPE."
|
55
|
+
method_option :account, :type => :string, :default => nil,
|
56
|
+
:aliases => %w(--org --organization)
|
57
|
+
define_method "config:remove" do |scope, key|
|
58
|
+
params = {:repo => true}
|
59
|
+
if scope == 'suite' then
|
60
|
+
params[:suite] = true
|
61
|
+
end
|
62
|
+
if options[:account] then
|
63
|
+
params[:account] = options[:account]
|
64
|
+
end
|
65
|
+
solano_setup(params)
|
66
|
+
|
67
|
+
begin
|
68
|
+
say Text::Process::REMOVE_CONFIG % [key, scope]
|
69
|
+
result = @solano_api.delete_config_key(scope, key)
|
70
|
+
say Text::Process::REMOVE_CONFIG_DONE % [key, scope]
|
71
|
+
rescue TddiumClient::Error::API => e
|
72
|
+
exit_failure Text::Error::REMOVE_CONFIG_ERROR
|
73
|
+
rescue Exception => e
|
74
|
+
exit_failure e.message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (c) 2011-2016 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'json'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Solano
|
8
|
+
class SolanoCli < Thor
|
9
|
+
desc "console [COMMAND]", "Open an ssh Debug Console to the Solano worker, execute command if given else start shell."
|
10
|
+
method_option :json, :type => :boolean, :default => false
|
11
|
+
method_option :commit, :type => :string, :default => nil
|
12
|
+
def console(*cmd)
|
13
|
+
solano_setup({:repo => true})
|
14
|
+
origin = `git config --get remote.origin.url`.strip
|
15
|
+
session_result = @solano_api.call_api(:get, "/sessions", {:repo_url => origin})["sessions"]
|
16
|
+
if session_result.length > 0 then
|
17
|
+
session = session_result[0]
|
18
|
+
session_id = session["id"]
|
19
|
+
q_result = @solano_api.query_session(session_id).tddium_response["session"]
|
20
|
+
suite_id = q_result["suite_id"]
|
21
|
+
start_result = @solano_api.start_console(session_id, suite_id).tddium_response
|
22
|
+
session_id = start_result["interactive_session_id"] # the new interactive session's id
|
23
|
+
if start_result["message"] == "interactive started" then
|
24
|
+
say "Starting console session #{session_id}"
|
25
|
+
ssh_command = nil
|
26
|
+
failures = 0
|
27
|
+
while !ssh_command do
|
28
|
+
sleep(Default::SLEEP_TIME_BETWEEN_POLLS)
|
29
|
+
begin
|
30
|
+
session = @solano_api.query_session(session_id).tddium_response["session"]
|
31
|
+
failures = 0 # clear any previous transient failures
|
32
|
+
rescue Exception => e
|
33
|
+
failures += 1
|
34
|
+
say e.to_s
|
35
|
+
session = {}
|
36
|
+
end
|
37
|
+
if failures > 2 then
|
38
|
+
say "Errors connecting to server"
|
39
|
+
return # give up.
|
40
|
+
end
|
41
|
+
if session["stage2_ready"] && session["ssh_command"] then
|
42
|
+
if cmd then
|
43
|
+
ssh_command = "#{session['ssh_command']} -o StrictHostKeyChecking=no \"#{cmd.join(' ')}\""
|
44
|
+
else
|
45
|
+
ssh_command = "#{session['ssh_command']} -o StrictHostKeyChecking=no"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
say "SSH Command is #{ssh_command}"
|
50
|
+
# exec terminates this ruby process and lets user control the ssh i/o
|
51
|
+
exec ssh_command
|
52
|
+
elsif start_result["message"] == "interactive already running"
|
53
|
+
dur = duration(Time.parse(start_result['session']['expires_at']) - Time.now)
|
54
|
+
say "Interactive session already running (expires in #{dur})"
|
55
|
+
session_id = start_result["session"]["id"]
|
56
|
+
session = @solano_api.query_session(session_id).tddium_response["session"]
|
57
|
+
if cmd then
|
58
|
+
exec "#{session['ssh_command']} -o StrictHostKeyChecking=no \"#{cmd.join(' ')}\""
|
59
|
+
else
|
60
|
+
exec "#{session['ssh_command']} -o StrictHostKeyChecking=no"
|
61
|
+
end
|
62
|
+
else
|
63
|
+
say start_result["message"]
|
64
|
+
end
|
65
|
+
else
|
66
|
+
say "Unable to find any previous sessions. Execute solano run first"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
# return nice string version of hrs mins secs from time delta
|
72
|
+
def duration(d)
|
73
|
+
secs = d.to_int
|
74
|
+
mins = secs / 60
|
75
|
+
hours = mins / 60
|
76
|
+
if hours > 0 then
|
77
|
+
"#{hours} hours #{mins % 60} minutes"
|
78
|
+
elsif mins > 0 then
|
79
|
+
"#{mins} minutes #{secs % 60} seconds"
|
80
|
+
else
|
81
|
+
"#{secs} seconds"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
map "show" => :describe
|
6
|
+
desc "describe [SESSION]", "Describe the state of a session, if it
|
7
|
+
is provided; otherwise, the latest session on current branch."
|
8
|
+
method_option :account, :type => :string, :default => nil,
|
9
|
+
:aliases => %w(--org --organization)
|
10
|
+
method_option :all, :type=>:boolean, :default=>false
|
11
|
+
method_option :type, :type=>:string, :default=>nil
|
12
|
+
method_option :json, :type=>:boolean, :default=>false
|
13
|
+
method_option :names, :type=>:boolean, :default=>false
|
14
|
+
method_option :verbose, :type=>:boolean, :default=>false
|
15
|
+
def describe(session_id=nil)
|
16
|
+
solano_setup({:repo => false})
|
17
|
+
|
18
|
+
status_message = ''
|
19
|
+
if !session_id then
|
20
|
+
# params to get the most recent session id on current branch
|
21
|
+
suite_params = {
|
22
|
+
:suite_id => @solano_api.current_suite_id,
|
23
|
+
:active => false,
|
24
|
+
:limit => 1
|
25
|
+
} if suite_for_current_branch?
|
26
|
+
|
27
|
+
sessions = suite_params ? @solano_api.get_sessions(suite_params) : []
|
28
|
+
if sessions.empty? then
|
29
|
+
exit_failure Text::Status::NO_INACTIVE_SESSION
|
30
|
+
end
|
31
|
+
|
32
|
+
session_id = sessions[0]['id']
|
33
|
+
|
34
|
+
session_status = sessions[0]['status'].upcase
|
35
|
+
session_commit = sessions[0]['commit']
|
36
|
+
current_commit = @scm.current_commit
|
37
|
+
if session_commit == current_commit
|
38
|
+
commit_message = "equal to your current commit"
|
39
|
+
else
|
40
|
+
cnt_ahead = @scm.number_of_commits(session_commit, current_commit)
|
41
|
+
if cnt_ahead == 0
|
42
|
+
cnt_behind = @scm.number_of_commits(current_commit, session_commit)
|
43
|
+
commit_message = "your workspace is behind by #{cnt_behind} commits"
|
44
|
+
else
|
45
|
+
commit_message = "your workspace is ahead by #{cnt_ahead} commits"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
duration = sessions[0]['duration']
|
50
|
+
start_timeago = "%s ago" % Solano::TimeFormat.seconds_to_human_time(Time.now - Time.parse(sessions[0]["start_time"]))
|
51
|
+
if duration.nil?
|
52
|
+
finish_timeago = "no info about duration found, started #{start_timeago}"
|
53
|
+
elsif session_status == 'RUNNING'
|
54
|
+
finish_timeago = "in process, started #{start_timeago}"
|
55
|
+
else
|
56
|
+
finish_time = Time.parse(sessions[0]["start_time"]) + duration
|
57
|
+
finish_timeago = "%s ago" % Solano::TimeFormat.seconds_to_human_time(Time.now - finish_time)
|
58
|
+
end
|
59
|
+
|
60
|
+
status_message = Text::Status::SESSION_STATUS % [session_commit, commit_message, session_status, finish_timeago]
|
61
|
+
end
|
62
|
+
|
63
|
+
result = @solano_api.query_session_tests(session_id)
|
64
|
+
|
65
|
+
session_result = Hash.new
|
66
|
+
if options[:verbose] then
|
67
|
+
session_result = @solano_api.query_session(session_id)
|
68
|
+
end
|
69
|
+
|
70
|
+
filtered = result['session']['tests']
|
71
|
+
if !options[:all]
|
72
|
+
filtered = filtered.select{|x| x['status'] == 'failed'}
|
73
|
+
end
|
74
|
+
|
75
|
+
if options[:type]
|
76
|
+
filtered = filtered.select{|x| x['test_type'].downcase == options[:type].downcase}
|
77
|
+
end
|
78
|
+
|
79
|
+
if options[:json]
|
80
|
+
json = result['session']
|
81
|
+
json['session'] = session_result['session']
|
82
|
+
puts JSON.pretty_generate(json)
|
83
|
+
elsif options[:names]
|
84
|
+
say filtered.map{|x| x['test_name']}.join(" ")
|
85
|
+
else
|
86
|
+
filtered.sort!{|a,b| [a['test_type'], a['test_name']] <=> [b['test_type'], b['test_name']]}
|
87
|
+
|
88
|
+
say Text::Process::DESCRIBE_SESSION % [session_id, status_message, options[:all] ? 'all' : 'failed']
|
89
|
+
|
90
|
+
table =
|
91
|
+
[["Test", "Status", "Duration"],
|
92
|
+
["----", "------", "--------"]] +
|
93
|
+
filtered.map do |x|
|
94
|
+
[
|
95
|
+
x['test_name'],
|
96
|
+
x['status'],
|
97
|
+
x['elapsed_time'] ? "#{x['elapsed_time']}s" : "-"
|
98
|
+
]
|
99
|
+
end
|
100
|
+
print_table table
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "find_failing FILES", "Find failing ordering for ruby specs by binary searching a failing test run"
|
6
|
+
desc "find_failing files+ failing_file", "Find out which file causes pollution / makes the failing file fail"
|
7
|
+
def find_failing(*files)
|
8
|
+
solano_setup({:repo => true})
|
9
|
+
|
10
|
+
failing = files.pop
|
11
|
+
if !files.include?(failing)
|
12
|
+
exit_failure "Files have to include the failing file, use the copy helper"
|
13
|
+
elsif files.size < 2
|
14
|
+
exit_failure "Files have to be more than 2, use the copy helper"
|
15
|
+
elsif !success?([failing])
|
16
|
+
exit_failure "#{failing} fails when run on it's own"
|
17
|
+
elsif success?(files)
|
18
|
+
exit_failure "tests pass locally"
|
19
|
+
else
|
20
|
+
loop do
|
21
|
+
a = remove_from(files, files.size / 2, :not => failing)
|
22
|
+
b = files - (a - [failing])
|
23
|
+
status, files = find_failing_set([a, b], failing)
|
24
|
+
if status == :finished
|
25
|
+
say "Fails when #{files.join(", ")} are run together"
|
26
|
+
break
|
27
|
+
elsif status == :continue
|
28
|
+
next
|
29
|
+
else
|
30
|
+
exit_failure "unable to isolate failure to 2 files"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def find_failing_set(sets, failing)
|
39
|
+
sets.each do |set|
|
40
|
+
next if set == [failing]
|
41
|
+
if !success?(set)
|
42
|
+
if set.size == 2
|
43
|
+
return [:finished, set]
|
44
|
+
else
|
45
|
+
return [:continue, set]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return [:failure, []]
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_from(set, x, options)
|
53
|
+
set.dup.delete_if { |f| f != options[:not] && (x -= 1) >= 0 }
|
54
|
+
end
|
55
|
+
|
56
|
+
def success?(files)
|
57
|
+
command = "bundle exec ruby #{files.map { |f| "-r./#{f.sub(/\.rb$/, "")}" }.join(" ")} -e ''"
|
58
|
+
say "Running: #{command}"
|
59
|
+
status = system(command)
|
60
|
+
say "Status: #{status ? "Success" : "Failure"}"
|
61
|
+
status
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (c) 2011-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
module Solano
|
4
|
+
class SolanoCli < Thor
|
5
|
+
desc "heroku", "Connect Heroku account with Solano CI (deprecated)"
|
6
|
+
method_option :email, :type => :string, :default => nil
|
7
|
+
method_option :password, :type => :string, :default => nil
|
8
|
+
method_option :ssh_key_file, :type => :string, :default => nil
|
9
|
+
method_option :app, :type => :string, :default => nil
|
10
|
+
def heroku
|
11
|
+
say "To activate your heroku account, please visit"
|
12
|
+
say "https://ci.solanolabs.com/"
|
13
|
+
|
14
|
+
solano_setup({:scm => false})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Copyright (c) 2012-2015 Solano Labs All Rights Reserved
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Solano
|
6
|
+
class SolanoCli < Thor
|
7
|
+
desc "hg:mirror", "Construct local hg -> git mirror"
|
8
|
+
method_option :noop, :type => :boolean, :default => false
|
9
|
+
method_option :force, :type => :boolean, :default => false
|
10
|
+
define_method "hg:mirror" do |*args|
|
11
|
+
solano_setup({:repo => true, :deprecated => true})
|
12
|
+
|
13
|
+
if @scm.scm_name != 'hg' then
|
14
|
+
exit_failure("Current repository does not appear to be using Mercurial")
|
15
|
+
end
|
16
|
+
|
17
|
+
if @scm.origin_url.nil? then
|
18
|
+
exit_failure("Missing default path; please set default path in hgrc")
|
19
|
+
end
|
20
|
+
|
21
|
+
if File.exists?(@scm.mirror_path) then
|
22
|
+
if !options[:force] then
|
23
|
+
exit_failure("Mirror already exists; use --force to recreate")
|
24
|
+
end
|
25
|
+
if options[:noop] then
|
26
|
+
exit_failure("Running in no-op mode; not removing existing mirror")
|
27
|
+
end
|
28
|
+
FileUtils.rm_rf(@scm.mirror_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
FileUtils.mkdir_p(@scm.mirror_path)
|
32
|
+
|
33
|
+
Solano::Scripts.prepend_script_path
|
34
|
+
|
35
|
+
clone_command = "git clone hg::#{@scm.root} #{@scm.mirror_path}"
|
36
|
+
# origin_command = "cd #{@scm.mirror_path} && git remote set-url origin #{@scm.origin_url}"
|
37
|
+
|
38
|
+
if options[:noop] then
|
39
|
+
puts "export PATH=#{ENV['PATH']}"
|
40
|
+
puts clone_command
|
41
|
+
# puts origin_command
|
42
|
+
else
|
43
|
+
Kernel.system(clone_command)
|
44
|
+
# Kernel.system(origin_command)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|