designshell 0.0.1
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.
- data/.gitignore +18 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyleSettings.xml +13 -0
- data/.idea/compiler.xml +25 -0
- data/.idea/copyright/profiles_settings.xml +5 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +11 -0
- data/.idea/modules.xml +11 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +9 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +196 -0
- data/LICENSE +22 -0
- data/README.md +35 -0
- data/README.rdoc +6 -0
- data/Rakefile +46 -0
- data/bin/designshelld.example.sh +5 -0
- data/bin/designshelld.example2.sh +3 -0
- data/bin/designshellserver +22 -0
- data/bin/ds +177 -0
- data/designshell.gemspec +40 -0
- data/designshell.iml +84 -0
- data/designshell.rdoc +5 -0
- data/features/designshell.feature +8 -0
- data/features/step_definitions/designshell_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/lib/buzzcore_mods.rb +19 -0
- data/lib/designshell/context.rb +48 -0
- data/lib/designshell/core.rb +78 -0
- data/lib/designshell/deploy_plan.rb +40 -0
- data/lib/designshell/key_chain.rb +40 -0
- data/lib/designshell/repo.rb +112 -0
- data/lib/designshell/repo_server.rb +25 -0
- data/lib/designshell/site_client.rb +141 -0
- data/lib/designshell/utils.rb +18 -0
- data/lib/designshell/version.rb +3 -0
- data/lib/designshell.rb +19 -0
- data/lib/designshellserver/command.rb +180 -0
- data/lib/designshellserver/core.rb +41 -0
- data/lib/designshellserver.rb +17 -0
- data/spec/KeyChain_spec.rb +94 -0
- data/spec/RepoServer_spec.rb +54 -0
- data/spec/Repo_spec.rb +105 -0
- data/spec/build_spec.rb +29 -0
- data/spec/client_to_server_spec.rb +111 -0
- data/spec/designshell_context_spec.rb +18 -0
- data/spec/designshell_core_spec.rb +45 -0
- data/spec/rspec_helper.rb +8 -0
- data/spec/server/deploy_spec.rb +210 -0
- data/spec/server/dummy_spec.rb +52 -0
- data/spec/site_client_spec.rb +90 -0
- data/test/default_test.rb +14 -0
- data/test/test_helper.rb +9 -0
- data/testmart.iml +9 -0
- metadata +390 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module DesignShell
|
2
|
+
module Utils
|
3
|
+
def self.lookupItems(aDeployNode, aKeyChain)
|
4
|
+
result = {}
|
5
|
+
REXML::XPath.each(aDeployNode,'item') do |n|
|
6
|
+
name = n.attribute('name').to_s.to_nil
|
7
|
+
key = n.attribute('key').to_s.to_nil || name
|
8
|
+
next unless name
|
9
|
+
if text = n.text.to_nil # value in node
|
10
|
+
result[name] = text
|
11
|
+
else # value in @params['deploy_creds']
|
12
|
+
result[key] = aKeyChain.get(key.to_sym) if key
|
13
|
+
end
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/designshell.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'designshell/version'
|
2
|
+
require 'osx_keychain'
|
3
|
+
require 'gli'
|
4
|
+
require 'git'
|
5
|
+
require 'buzzcore'
|
6
|
+
require 'buzzcore_mods'
|
7
|
+
require 'termios'
|
8
|
+
require 'highline/import'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'net/ssh'
|
11
|
+
require 'uri'
|
12
|
+
|
13
|
+
require 'designshell/utils'
|
14
|
+
require 'designshell/context'
|
15
|
+
require 'designshell/key_chain'
|
16
|
+
require 'designshell/repo'
|
17
|
+
require 'designshell/repo_server'
|
18
|
+
require 'designshell/deploy_plan'
|
19
|
+
require 'designshell/core'
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module DesignShellServer
|
2
|
+
class Command
|
3
|
+
|
4
|
+
attr_accessor :core,:context,:line,:command,:id,:params,:repo
|
5
|
+
|
6
|
+
def initialize(aCore,aLine,aCommandName=nil)
|
7
|
+
@core = aCore
|
8
|
+
@context = aCore && aCore.context
|
9
|
+
@line = aLine
|
10
|
+
tl = aLine.dup
|
11
|
+
cmd = tl.extract!(/^[A-Z0-9_]+/)
|
12
|
+
@command = aCommandName || cmd
|
13
|
+
tl.bite! ' '
|
14
|
+
@id = tl.extract!(/^[a-z0-9]+/)
|
15
|
+
tl.bite! ' '
|
16
|
+
@params = ::JSON.parse(tl) if @params = tl.to_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute
|
20
|
+
self.send @command.to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
def writeline(aString)
|
24
|
+
@context.stdout.puts aString
|
25
|
+
end
|
26
|
+
|
27
|
+
# Prepares repo in cache dir for site
|
28
|
+
# requires params: repo_url,site
|
29
|
+
def prepare_cache # {:url=>'git://github.com/ddssda', :branch=>'master', :commit=>'ad452bcd'}
|
30
|
+
url = @params['repo_url']
|
31
|
+
site = @params['site']
|
32
|
+
wd = @core.working_dir_from_site(site)
|
33
|
+
|
34
|
+
@repo = DesignShell::Repo.new
|
35
|
+
suitable = if File.exists?(wd)
|
36
|
+
@repo.open wd
|
37
|
+
@repo.origin.url==url
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
if suitable
|
43
|
+
@repo.fetch
|
44
|
+
else
|
45
|
+
if File.exists? wd
|
46
|
+
raise RuntimeError.new('almost did bad delete') if !@core.cache_dir || @core.cache_dir.length<3 || !wd.begins_with?(@core.cache_dir)
|
47
|
+
FileUtils.rm_rf wd
|
48
|
+
end
|
49
|
+
@repo.clone(url, wd)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Switches @repo to given branch and/or commit
|
54
|
+
# Should call prepare_cache first to create @repo
|
55
|
+
# requires params: branch and/or commit
|
56
|
+
def checkout_branch_commit
|
57
|
+
#url = @params['repo_url']
|
58
|
+
#site = @params['site']
|
59
|
+
#wd = @core.working_dir_from_site(site)
|
60
|
+
branch = @params['branch'] || 'master'
|
61
|
+
commit = @params['commit']
|
62
|
+
@repo.checkout(commit,branch)
|
63
|
+
#perhaps use reset --hard here
|
64
|
+
if (commit)
|
65
|
+
@repo.merge(commit,['--ff-only'])
|
66
|
+
else
|
67
|
+
@repo.merge('origin/'+branch,['--ff-only'])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Determines whether to do an incremental or complete deploy and deploys current files in repo working dir to repo_url
|
72
|
+
# requires :
|
73
|
+
# uses: site_client.deploy_status
|
74
|
+
# params: deploy_cred
|
75
|
+
def deploy
|
76
|
+
deployPlanString = @repo.get_file_content('.deploy_plan.xml',@params['commit']||@params['branch'])
|
77
|
+
xmlRoot = XmlUtils.get_xml_root(deployPlanString)
|
78
|
+
# select plan
|
79
|
+
planNode = XmlUtils.single_node(xmlRoot,'plan')
|
80
|
+
# for each deploy
|
81
|
+
deployNode = XmlUtils.single_node(planNode,'deploy')
|
82
|
+
# create client for kind/method
|
83
|
+
@site_client = DesignShell::SiteClient.new({
|
84
|
+
:site_url => @params['site_url'],
|
85
|
+
:site_username => @params['site_username'],
|
86
|
+
:site_password => @params['site_password'],
|
87
|
+
})
|
88
|
+
ds = @site_client.deploy_status
|
89
|
+
site_repo_url = ds && ds['repo_url'].to_nil
|
90
|
+
site_branch = ds && ds['branch'].to_nil
|
91
|
+
site_commit = ds && ds['commit'].to_nil
|
92
|
+
repo_url = @repo.url
|
93
|
+
# @todo must limit uploads to build folder
|
94
|
+
fromPath = MiscUtils.ensure_slashes(XmlUtils.peek_node_value(deployNode,'fromPath','/'),false,true) # eg. /build/bigcommerce effectively selects a subfolder that should be debased
|
95
|
+
toPath = MiscUtils.ensure_slashes(XmlUtils.peek_node_value(deployNode,'toPath','/'),false,true) # eg. / effectively the new base for these files
|
96
|
+
if site_repo_url && site_repo_url==repo_url && site_branch && site_commit
|
97
|
+
# incremental
|
98
|
+
changes = @repo.changesBetweenCommits(site_commit,@repo.head.to_s)
|
99
|
+
uploads,deletes = convertChangesToUploadsDeletes(changes)
|
100
|
+
uploads.delete_if { |fp| !fp.begins_with?(fromPath) }
|
101
|
+
deletes.delete_if { |fp| !fp.begins_with?(fromPath) }
|
102
|
+
@site_client.delete_files(deletes,fromPath,toPath)
|
103
|
+
@site_client.upload_files(@repo.path,uploads,fromPath,toPath)
|
104
|
+
@site_client.deploy_status = {
|
105
|
+
:repo_url => @repo.url,
|
106
|
+
:branch => @repo.branch,
|
107
|
+
:commit => @repo.head.to_s,
|
108
|
+
:fromPath => fromPath,
|
109
|
+
:toPath => toPath
|
110
|
+
}
|
111
|
+
else
|
112
|
+
# complete
|
113
|
+
# for now, just deploy all files in wd, creating folders as necessary
|
114
|
+
# later, delete remote files not in wd except for eg. .deploy-status.xml and perhaps upload folders
|
115
|
+
uploads = MiscUtils.recursive_file_list(@repo.path,false)
|
116
|
+
uploads.delete_if do |fp|
|
117
|
+
!fp.begins_with?(fromPath) || fp.begins_with?('.git/')
|
118
|
+
end
|
119
|
+
@site_client.upload_files(@repo.path,uploads,fromPath,toPath)
|
120
|
+
@site_client.deploy_status = {
|
121
|
+
:repo_url => @repo.url,
|
122
|
+
:branch => @repo.branch,
|
123
|
+
:commit => @repo.head.to_s,
|
124
|
+
:fromPath => fromPath,
|
125
|
+
:toPath => toPath
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, ...) changed (T)
|
131
|
+
def convertChangesToUploadsDeletes(changes)
|
132
|
+
uploads = []
|
133
|
+
deletes = []
|
134
|
+
changes.each do |line|
|
135
|
+
continue if line==""
|
136
|
+
tabi = line.index("\t")
|
137
|
+
status = line[0,tabi]
|
138
|
+
path = line[tabi+1..-1]
|
139
|
+
if status.index('D')
|
140
|
+
deletes << path
|
141
|
+
else
|
142
|
+
uploads << path
|
143
|
+
end
|
144
|
+
end
|
145
|
+
return uploads,deletes
|
146
|
+
end
|
147
|
+
|
148
|
+
def DUMMY
|
149
|
+
id = StringUtils.random_word(8,8)
|
150
|
+
writeline "RECEIVED "+id
|
151
|
+
sleep 1
|
152
|
+
detail = ::JSON.generate({:this=>5, :that=>'ABC'}) #JSON.parse(document) or JSON.generate(data)
|
153
|
+
writeline ['PROGRESS',id,detail].join(' ')
|
154
|
+
sleep 1
|
155
|
+
detail = ::JSON.generate({:result=>123}) #JSON.parse(document) or JSON.generate(data)
|
156
|
+
writeline ['COMPLETE',id,detail].join(' ')
|
157
|
+
end
|
158
|
+
|
159
|
+
def QUICK
|
160
|
+
id = StringUtils.random_word(8,8)
|
161
|
+
writeline "RECEIVED "+id
|
162
|
+
writeline "COMPLETE "+id
|
163
|
+
end
|
164
|
+
|
165
|
+
def DEPLOY # {}
|
166
|
+
id = StringUtils.random_word(8,8)
|
167
|
+
writeline "RECEIVED "+id
|
168
|
+
detail =
|
169
|
+
writeline ['PROGRESS',id,::JSON.generate({:message => 'preparing cache'})].join(' ')
|
170
|
+
prepare_cache
|
171
|
+
writeline ['PROGRESS',id,::JSON.generate({:message => 'checkout'})].join(' ')
|
172
|
+
checkout_branch_commit
|
173
|
+
writeline ['PROGRESS',id,::JSON.generate({:message => 'deploying'})].join(' ')
|
174
|
+
deploy
|
175
|
+
writeline "COMPLETE "+id
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module DesignShellServer
|
2
|
+
class Core
|
3
|
+
|
4
|
+
attr_reader :context
|
5
|
+
|
6
|
+
def initialize(aContext)
|
7
|
+
@context = aContext
|
8
|
+
end
|
9
|
+
|
10
|
+
def make_command(aLine)
|
11
|
+
command_name = aLine.scan(/^[A-Z0-9_]+/).pop.to_nil
|
12
|
+
return nil unless command_name && DesignShellServer::Command.instance_methods.include?(command_name)
|
13
|
+
return DesignShellServer::Command.new(self,aLine,command_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
if line = ENV['SSH_ORIGINAL_COMMAND']
|
18
|
+
command = make_command(line)
|
19
|
+
command.execute
|
20
|
+
else
|
21
|
+
@context.stdout.print "\n>"
|
22
|
+
@context.stdin.each_line do |line| line.chomp! "\n"
|
23
|
+
command = make_command(line)
|
24
|
+
command.execute
|
25
|
+
@context.stdout.print "\n>"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def cache_dir
|
31
|
+
@cache_dir ||= MiscUtils.append_slash(@context.credentials[:cache_dir] || MiscUtils.make_temp_dir('DesignShellServer'))
|
32
|
+
end
|
33
|
+
|
34
|
+
def working_dir_from_site(aSite)
|
35
|
+
return nil unless aSite
|
36
|
+
aSite.gsub!(/[^a-zA-Z0-9.\-_]/,'_')
|
37
|
+
File.join(cache_dir,aSite)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'git'
|
2
|
+
require 'buzzcore'
|
3
|
+
require 'buzzcore_mods'
|
4
|
+
require 'net/dav'
|
5
|
+
require 'json'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
#require 'termios'
|
10
|
+
#require 'highline/import'
|
11
|
+
|
12
|
+
require 'designshell/context'
|
13
|
+
require 'designshell/site_client'
|
14
|
+
require 'designshell/deploy_plan'
|
15
|
+
require 'designshell/repo'
|
16
|
+
require 'designshellserver/core'
|
17
|
+
require 'designshellserver/command'
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
|
4
|
+
describe "KeyChain" do
|
5
|
+
|
6
|
+
keyChain = nil
|
7
|
+
|
8
|
+
before do
|
9
|
+
keyChain = DesignShell::KeyChain.new('DesignShellTest')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should write,read,check value" do
|
13
|
+
value = StringUtils.random_word(8,8)
|
14
|
+
keyChain.set('testKey',value)
|
15
|
+
readValue = keyChain.get('testKey')
|
16
|
+
readValue.should == value
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should support get and set with a prefix" do
|
20
|
+
value1 = StringUtils.random_word(8,8)
|
21
|
+
value2 = StringUtils.random_word(8,8)
|
22
|
+
keyChain.set('testKey',value1)
|
23
|
+
keyChain.set('testKey',value2,'blah')
|
24
|
+
keyChain.get('testKey').should==value1
|
25
|
+
keyChain.get('testKey','blah').should==value2
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should support multiple get" do
|
29
|
+
value1 = StringUtils.random_word(8,8)
|
30
|
+
value2 = StringUtils.random_word(8,8)
|
31
|
+
keyChain.set('testKey1',value1)
|
32
|
+
keyChain.set('testKey2',value2)
|
33
|
+
keyChain.get('testKey1').should==value1
|
34
|
+
keyChain.get('testKey2').should==value2
|
35
|
+
keyChain.get(['testKey1']).should=={'testKey1' => value1}
|
36
|
+
keyChain.get(['testKey2']).should=={'testKey2' => value2}
|
37
|
+
keyChain.get(['testKey1','testKey2']).should=={'testKey1' => value1,'testKey2' => value2}
|
38
|
+
keyChain.get(%w(testKey1 testKey2)).should=={'testKey1' => value1,'testKey2' => value2}
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should support multiple get with a prefix" do
|
42
|
+
value1 = StringUtils.random_word(8,8)
|
43
|
+
value2 = StringUtils.random_word(8,8)
|
44
|
+
keyChain.set('testKey1','')
|
45
|
+
keyChain.set('testKey2','')
|
46
|
+
keyChain.set('testKey1',value1,'prefix1.')
|
47
|
+
keyChain.set('testKey2',value2,'prefix1.')
|
48
|
+
keyChain.get(%w(testKey1 testKey2)).should == {'testKey1' => '', 'testKey2' => ''}
|
49
|
+
keyChain.get(%w(testKey1 testKey2),'prefix1.').should == {'testKey1' => value1, 'testKey2' => value2}
|
50
|
+
keyChain.get(%w(testKey1 testKey2),'prefix1.',true).should == {'prefix1.testKey1' => value1, 'prefix1.testKey2' => value2}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should support multiple set" do
|
54
|
+
value1 = StringUtils.random_word(8,8)
|
55
|
+
value2 = StringUtils.random_word(8,8)
|
56
|
+
keyChain.set({
|
57
|
+
'testKey1' => value1,
|
58
|
+
'testKey2' => value2
|
59
|
+
})
|
60
|
+
keyChain.get('testKey1').should==value1
|
61
|
+
keyChain.get('testKey2').should==value2
|
62
|
+
end
|
63
|
+
|
64
|
+
DEPLOY_XML = <<EOS
|
65
|
+
<deploy>
|
66
|
+
<kind>BigCommerce</kind>
|
67
|
+
<method>WebDav</method>
|
68
|
+
<fromPath>/build/bigcommerce</fromPath>
|
69
|
+
<toPath>/</toPath>
|
70
|
+
<item name="itemX">some item x</item>
|
71
|
+
<item name="itemY" key="itemYYY">YYY</item>
|
72
|
+
<item name="itemZ"></item>
|
73
|
+
<item name="itemZZ"/>
|
74
|
+
</deploy>
|
75
|
+
EOS
|
76
|
+
|
77
|
+
it "should support DesignShell::Utils.lookupItems" do
|
78
|
+
values = {
|
79
|
+
'itemX' => 'never read this',
|
80
|
+
'itemY' => 'never read this',
|
81
|
+
'itemYYY' => 'YYYYY',
|
82
|
+
'itemZ' => 'ZZZ',
|
83
|
+
'itemZZ' => 'ZZZZZ',
|
84
|
+
}
|
85
|
+
keyChain.set(values)
|
86
|
+
deployXml = XmlUtils.get_xml_root(DEPLOY_XML)
|
87
|
+
result = DesignShell::Utils.lookupItems(deployXml,keyChain)
|
88
|
+
result['itemX'].should=='some item x'
|
89
|
+
result['itemY'].should=='YYY' # text value overrides keychain
|
90
|
+
result['itemZ'].should==values['itemZ']
|
91
|
+
result['itemZZ'].should==values['itemZZ']
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
describe "RepoServer" do
|
6
|
+
|
7
|
+
testFolder = nil
|
8
|
+
before do
|
9
|
+
testFolder = Dir.mktmpdir('Repo_spec-')
|
10
|
+
|
11
|
+
cred = Credentials.new(:designshell)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
FileUtils.rm_rf testFolder if testFolder
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should list repos" do
|
20
|
+
keyChain = DesignShell::KeyChain.new('DesignShell')
|
21
|
+
#keyChain.set({
|
22
|
+
# :oauth_token => 'OAuth consumer Key',
|
23
|
+
# :oauth_secret => 'OAuth consumer Secret',
|
24
|
+
# :login => 'username, not email address',
|
25
|
+
# :password => 'user password'
|
26
|
+
#},'RepoServer.')
|
27
|
+
repoServer = DesignShell::RepoServer.new
|
28
|
+
# should move values to credentials that looks up keyChain
|
29
|
+
values = keyChain.get([:oauth_token,:oauth_secret,:login,:password],'RepoServer.').symbolize_keys
|
30
|
+
repoServer.setup(values)
|
31
|
+
|
32
|
+
result = repoServer.repos #"[#<Hashie::Mash is_private=true name="test1" owner="buzzware" scm="git" slug="test1">]"
|
33
|
+
result.class.should==Array
|
34
|
+
result.length.should > 0
|
35
|
+
result.first.scm.should=='git'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should clone the first repo" do
|
39
|
+
keyChain = DesignShell::KeyChain.new('DesignShell')
|
40
|
+
repoServer = DesignShell::RepoServer.new
|
41
|
+
values = keyChain.get([:oauth_token,:oauth_secret,:login,:password],'RepoServer.').symbolize_keys
|
42
|
+
repoServer.setup(values)
|
43
|
+
repos = repoServer.repos
|
44
|
+
repos.length.should > 0
|
45
|
+
repo = repos && repos.first
|
46
|
+
|
47
|
+
url = "git@bitbucket.org:#{repo.owner}/#{repo.slug}.git"
|
48
|
+
repo = DesignShell::Repo.new
|
49
|
+
result = repo.clone(url, testFolder)
|
50
|
+
repo.path.should == testFolder
|
51
|
+
repo.branches.class.should == Git::Branches
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/spec/Repo_spec.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
describe "Repo" do
|
6
|
+
|
7
|
+
testFolder = nil
|
8
|
+
before do
|
9
|
+
testFolder = MiscUtils.real_path(Dir.mktmpdir('Repo_spec-'))
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
FileUtils.rm_rf testFolder if testFolder
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
COMMIT_RESULT1 = "[master (root-commit) 6bdd9e1] first commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file1.txt"
|
18
|
+
|
19
|
+
it "commit should create commit object or string message" do
|
20
|
+
repo = DesignShell::Repo.new
|
21
|
+
repo.init testFolder
|
22
|
+
|
23
|
+
file1 = File.join(testFolder,'file1.txt')
|
24
|
+
content11 = '11111'
|
25
|
+
MiscUtils.string_to_file(content11,file1)
|
26
|
+
repo.add 'file1.txt'
|
27
|
+
commit1 = repo.commit_all('first commit')
|
28
|
+
commit1.class.should == Git::Object::Commit
|
29
|
+
|
30
|
+
commit2 = repo.commit_all('second commit without changes')
|
31
|
+
commit2.should == nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "create a repo, add file, commit, change, commit, reset, check" do
|
35
|
+
repo = DesignShell::Repo.new
|
36
|
+
repo.init testFolder
|
37
|
+
repo.path.should == MiscUtils.real_path(testFolder)
|
38
|
+
|
39
|
+
file1 = File.join(testFolder,'file1.txt')
|
40
|
+
content11 = '11111'
|
41
|
+
MiscUtils.string_to_file(content11,file1)
|
42
|
+
repo.git.add 'file1.txt'
|
43
|
+
commit1 = repo.commit_all('first commit')
|
44
|
+
|
45
|
+
content12 = '11111-some more text'
|
46
|
+
MiscUtils.string_to_file(content12,file1)
|
47
|
+
commit2 = repo.commit_all('second commit')
|
48
|
+
|
49
|
+
read_content = MiscUtils.string_from_file(file1)
|
50
|
+
read_content.should == content12
|
51
|
+
|
52
|
+
repo.reset_hard(commit1)
|
53
|
+
|
54
|
+
read_content = MiscUtils.string_from_file(file1)
|
55
|
+
read_content.should == content11
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should download a remote repo and check log, then re-open it and check log again" do
|
59
|
+
repo = DesignShell::Repo.new
|
60
|
+
url = "git@github.com:buzzware/underscore_plus.git"
|
61
|
+
repo.clone(url, testFolder)
|
62
|
+
repo.path.should == testFolder
|
63
|
+
repo.log.first.class.should == Git::Object::Commit
|
64
|
+
|
65
|
+
repo = DesignShell::Repo.new
|
66
|
+
repo.open testFolder
|
67
|
+
repo.path.should == testFolder
|
68
|
+
repo.log.first.class.should == Git::Object::Commit
|
69
|
+
repo.origin.url==url
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should download a remote repo and get diffs between commits" do
|
73
|
+
repo = DesignShell::Repo.new
|
74
|
+
url = "git@github.com:buzzware/underscore_plus.git"
|
75
|
+
repo.clone(url, testFolder)
|
76
|
+
|
77
|
+
commit1 = "4b133ff8825bbd488ba61fa3e3b82a5fa746ac6a"
|
78
|
+
commit2 = "d1b8440dc730ceb4471fbe7c42ccfac94ea12799"
|
79
|
+
changes = repo.changesBetweenCommits(commit1,commit2)
|
80
|
+
changes.should==["A\tunderscore_plus.js"]
|
81
|
+
changes = repo.changesBetweenCommits(commit2,commit1)
|
82
|
+
changes.should==["D\tunderscore_plus.js"]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should get contents of a given file from a given commit" do
|
86
|
+
repo = DesignShell::Repo.new
|
87
|
+
url = "git@github.com:buzzware/underscore_plus.git"
|
88
|
+
repo.clone(url, testFolder)
|
89
|
+
|
90
|
+
commit1 = "4b133ff8825bbd488ba61fa3e3b82a5fa746ac6a"
|
91
|
+
commit2 = "d1b8440dc730ceb4471fbe7c42ccfac94ea12799"
|
92
|
+
file1 = "README.md"
|
93
|
+
file2 = "underscore_plus.js"
|
94
|
+
|
95
|
+
readme = repo.get_file_content(file1,commit1)
|
96
|
+
readme.is_a?(String).should==true
|
97
|
+
readme.size.should > 0
|
98
|
+
code = repo.get_file_content(file2,commit1)
|
99
|
+
code.should==nil
|
100
|
+
code = repo.get_file_content(file2,commit2)
|
101
|
+
code.is_a?(String).should==true
|
102
|
+
code.size.should > 0
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
data/spec/build_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
|
4
|
+
describe "build" do
|
5
|
+
|
6
|
+
testFolder = nil
|
7
|
+
before do
|
8
|
+
testFolder = Dir.mktmpdir('Repo_spec-')
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
FileUtils.rm_rf testFolder if testFolder
|
13
|
+
end
|
14
|
+
|
15
|
+
#it "should build source folder into build folder" do
|
16
|
+
# context = DesignShell::Context.new()
|
17
|
+
# ds = DesignShell::Core.new(:context => context)
|
18
|
+
# ds.build
|
19
|
+
#end
|
20
|
+
|
21
|
+
#it "should commit the repository" do
|
22
|
+
# context = DesignShell::Context.new()
|
23
|
+
# repo = DesignShell::Repo.new
|
24
|
+
# repo.configure()
|
25
|
+
# repo.clone("git@github.com:buzzware/underscore_plus.git", testFolder)
|
26
|
+
# ds = DesignShell::Core.new(:context => context, :repo => repo)
|
27
|
+
# ds.ensure_repo_open.commit_all(context)
|
28
|
+
#end
|
29
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
|
4
|
+
describe "client to server interaction" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@key_chain = DesignShell::KeyChain.new('DesignShellTest')
|
8
|
+
@credentials = Credentials.new('designshell')
|
9
|
+
Dir.chdir @credentials[:deploy_repo_path]
|
10
|
+
@context = DesignShell::Context.new(
|
11
|
+
:argv=>[],
|
12
|
+
:env=>{},
|
13
|
+
:stdout=>$stdout,
|
14
|
+
:stdin=>$stdin,
|
15
|
+
:stderr=>$stderr,
|
16
|
+
:key_chain=>@key_chain,
|
17
|
+
:credentials=>@credentials
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should call QUICK and get results" do
|
22
|
+
dash = DesignShell::Core.new(
|
23
|
+
:context => @context
|
24
|
+
)
|
25
|
+
result = dash.call_server_command('QUICK')
|
26
|
+
puts result
|
27
|
+
result.begins_with?('RECEIVED').should == true
|
28
|
+
result.index('COMPLETE').should >= 0
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should call deploy" do
|
32
|
+
dash = DesignShell::Core.new(
|
33
|
+
:context => @context
|
34
|
+
)
|
35
|
+
result = dash.deploy
|
36
|
+
puts result
|
37
|
+
result.begins_with?('RECEIVED').should == true
|
38
|
+
result.index('COMPLETE').should >= 0
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
#it "should connect to SSH server" do
|
44
|
+
# Net::SSH.start( @context.credentials[:deploy_host],nil) do |ssh|
|
45
|
+
#
|
46
|
+
# #result = ssh.exec!("ls")
|
47
|
+
# #puts result
|
48
|
+
#
|
49
|
+
#
|
50
|
+
# #ssh.open_channel{|channel| #get root privelages
|
51
|
+
# ##configure behavior of channel
|
52
|
+
# #channel.on_data{|channel, data|
|
53
|
+
# # puts "#{data}"
|
54
|
+
# # if data =~ /^Password:/
|
55
|
+
# # channel.send_data("#{PASSWORD}\n")
|
56
|
+
# # elsif data =~ /root@/
|
57
|
+
# # channel.exec("tail /some/log/file.txt")
|
58
|
+
# # channel.on_data{"STOP LOOPING, DAMN YOU!"}
|
59
|
+
# # end
|
60
|
+
# #channel.on_close... (etc.)
|
61
|
+
# #
|
62
|
+
# #channel.request_pty do |ch,success|
|
63
|
+
# # if success
|
64
|
+
# # puts "pty successfully obtained"
|
65
|
+
# # else
|
66
|
+
# # puts "could not obtain pty"
|
67
|
+
# # end end
|
68
|
+
# #
|
69
|
+
# #channel.exec("sudoshell"){|channel, win| #custom sudo script.
|
70
|
+
# # if win
|
71
|
+
# # puts "ss command sent"
|
72
|
+
# # else puts "ss command FAIL"
|
73
|
+
# # end
|
74
|
+
# #}
|
75
|
+
# #
|
76
|
+
#
|
77
|
+
# ssh.open_channel do |channel|
|
78
|
+
# channel.on_data do |ch, data|
|
79
|
+
# puts "got stdout: #{data}"
|
80
|
+
# #channel.send_data "something for stdin\n"
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# channel.on_extended_data do |ch, type, data|
|
84
|
+
# puts "got stderr: #{data}"
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# channel.on_close do |ch|
|
88
|
+
# puts "channel is closing!"
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# channel.request_pty do |ch,success|
|
92
|
+
# if success
|
93
|
+
# puts "pty successfully obtained"
|
94
|
+
# else
|
95
|
+
# puts "could not obtain pty"
|
96
|
+
# end
|
97
|
+
# end
|
98
|
+
# #sleep 1
|
99
|
+
# result = channel.exec("DEPLOY") do |ch, success|
|
100
|
+
# abort "could not execute command" unless success
|
101
|
+
# end
|
102
|
+
# channel.wait
|
103
|
+
# puts result
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# ssh.loop
|
107
|
+
#
|
108
|
+
# end
|
109
|
+
#end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec_helper"
|
3
|
+
|
4
|
+
describe "DesignShell::Context" do
|
5
|
+
|
6
|
+
it "should find repo path upward" do
|
7
|
+
tempdir = MiscUtils.real_path(MiscUtils.make_temp_dir('designshell_context_spec'))
|
8
|
+
Dir.mkdir(git_dir = File.join(tempdir,'.git'))
|
9
|
+
Dir.mkdir(File.join(tempdir,'one'))
|
10
|
+
orange = File.join(tempdir,'one/apple/orange')
|
11
|
+
FileUtils.mkpath(orange)
|
12
|
+
Dir.mkdir(File.join(tempdir,'two'))
|
13
|
+
Dir.chdir(orange)
|
14
|
+
context = DesignShell::Context.new({})
|
15
|
+
context.pwd.should==orange
|
16
|
+
context.find_git_root.should==tempdir
|
17
|
+
end
|
18
|
+
end
|