rigup 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 074cf53541cc8dda276109cd786eed5e4c013455
4
+ data.tar.gz: ba808e6dd94614a4f0cc179fe3dccd29f1c1f517
5
+ SHA512:
6
+ metadata.gz: d9ab780149ca55a6dca8bf1067bd723c00c532219e39196bcd8b5429c556a0bbccb790230c504c5fad0d638db0eb773436853df67dd5738d5b55f91dbd774127
7
+ data.tar.gz: a28e3901c130731e5792aa0683d11ec45534bd39840f4e4883b3861a88c33b545418c8cd2a4f1e711bbadb12f493181fc0fb227347f2375ca2376176f1be3876
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1 @@
1
+ Toolset for deployment
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/rigup ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require_relative '../lib/rigup.rb'
4
+
5
+ Rigup::Cli.start(ARGV)
@@ -0,0 +1,32 @@
1
+ require 'rigup'
2
+
3
+ # This file will be called deploy.thor and lives in the root of the project repositiory, so it is version controlled
4
+ # and can be freely modified to suit the project requirements
5
+ class Deploy < Rigup::DeployBase # from gem, sets context and loads rigup.yml into config from site_dir
6
+
7
+ # You are free to modify these two tasks to suit your requirements
8
+
9
+ desc 'install','install the freshly delivered files'
10
+ def install
11
+
12
+ # select_suffixed_file("/config/database.yml")
13
+ # select_suffixed_file("/yore.config.xml")
14
+ # select_suffixed_file("/config/app_config.xml")
15
+ # select_suffixed_file("/system/apache.site")
16
+ #make_public_cache_dir("/public/cache")
17
+
18
+ # ensure_link("/log","/log")
19
+ # ensure_link("/pids","/tmp/pids")
20
+ # ensure_link("/uploads","/tmp/uploads")
21
+ # ensure_link("/system","/public/system")
22
+
23
+ #run "touch /log/production.log && chown : /log/production.log && chmod 666 /log/production.log"
24
+ end
25
+
26
+ desc 'restart','restart the web server'
27
+ def restart
28
+ # run "touch " + File.join("current/tmp/restart.txt",@site_dir) # && chown user:group current/tmp/restart.txt"
29
+ # run "/etc/init.d/apache2 restart --force-reload"
30
+ end
31
+
32
+ end
data/lib/rigup/cli.rb ADDED
@@ -0,0 +1,159 @@
1
+ module Rigup
2
+ class Cli < Thor
3
+
4
+ include Rigup::Runability
5
+ include Rigup::InstallUtils
6
+
7
+ attr_reader :context, :release_path
8
+
9
+ no_commands do
10
+
11
+ def init(aPath=nil,aConfig={})
12
+ return if @initialised
13
+ @initialised = true
14
+ aPath ||= aConfig[:site_dir] || Dir.pwd
15
+ @site_dir = Buzztools::File.real_path(aPath) rescue File.expand_path(aPath)
16
+ @releases_path = File.join(@site_dir,'releases')
17
+ if File.exists?(f=File.join(@site_dir,'rigup.yml'))
18
+ file_config = YAML.load(String.from_file(f))
19
+ aConfig.merge!(file_config)
20
+ end
21
+ config = Rigup::Config.new(aConfig.merge(site_dir: @site_dir))
22
+ @context = Rigup::Context.new(
23
+ config: config,
24
+ logger: ::Logger.new(STDOUT),
25
+ pwd: Dir.pwd
26
+ )
27
+ end
28
+
29
+ def site_dir
30
+ @site_dir
31
+ end
32
+
33
+ def cache_dir
34
+ File.join(@site_dir,'shared','cached-copy')
35
+ end
36
+
37
+ def config
38
+ @context.config
39
+ end
40
+
41
+ def repo
42
+ @repo ||= GitRepo.new(@context)
43
+ end
44
+
45
+ # Prepares repo in cache dir for site
46
+ # requires params: repo_url,site
47
+ def prepare_cache # {:url=>'git://github.com/ddssda', :branch=>'master', :commit=>'ad452bcd'}
48
+ url = config[:git_url]
49
+ wd = cache_dir
50
+
51
+ suitable = if File.exists?(wd)
52
+ repo.open wd
53
+ repo.origin.url==url
54
+ else
55
+ false
56
+ end
57
+
58
+ if suitable
59
+ repo.fetch
60
+ else
61
+ if File.exists? wd
62
+ #raise RuntimeError.new('almost did bad delete') if !@core.cache_dir || @core.cache_dir.length<3 || !wd.begins_with?(@core.cache_dir)
63
+ FileUtils.rm_rf wd
64
+ end
65
+ repo.clone(url, wd)
66
+ end
67
+ end
68
+
69
+ # Switches @repo to given branch and/or commit
70
+ # Should call prepare_cache first to create @repo
71
+ # requires params: branch and/or commit
72
+ def checkout_branch_commit
73
+ branch = config[:branch] || 'master'
74
+ commit = config[:commit]
75
+ repo.open(cache_dir)
76
+ repo.checkout(commit,branch)
77
+ #perhaps use reset --hard here
78
+ if (commit)
79
+ repo.merge(commit,['--ff-only'])
80
+ else
81
+ repo.merge('origin/'+branch,['--ff-only'])
82
+ end
83
+ end
84
+
85
+ def update_cache(aPath=nil)
86
+ prepare_cache
87
+ checkout_branch_commit
88
+ end
89
+
90
+ def release
91
+ release = Time.now.strftime('%Y%m%d%H%M%S')
92
+ @release_path = File.expand_path(release,@releases_path)
93
+ repo.open(cache_dir)
94
+ repo.export(@release_path)
95
+ release_config = context.config.to_hash
96
+ release_config[:commit] = repo.head.sha
97
+ release_config[:branch] = repo.branch
98
+ release_config.to_yaml.to_file(File.join(@release_path,'rigup.yml'))
99
+ return @release_path
100
+ end
101
+
102
+ def link_live
103
+ ensure_link(@release_path,File.expand_path(File.join(site_dir,'current')))
104
+ end
105
+
106
+ def cleanup
107
+ @releases = run("ls -x #{@releases_path}").split.sort
108
+ count = (@keep_releases || 3).to_i
109
+ if count >= @releases.length
110
+ @context.logger.info "no old releases to clean up"
111
+ else
112
+ @context.logger.info "keeping #{count} of #{@releases.length} deployed releases"
113
+
114
+ directories = (@releases - @releases.last(count)).map { |r|
115
+ File.join(@releases_path, r)
116
+ }.join(" ")
117
+
118
+ run "rm -rf #{directories}"
119
+ end
120
+ end
121
+
122
+ def call_release_command(aCommand)
123
+ return unless cmdline = config["#{aCommand}_command".to_sym].to_s.strip.to_nil
124
+ run cmdline, @release_path
125
+ end
126
+
127
+ end
128
+
129
+ public
130
+
131
+ desc "new GIT_URL [PATH]", "setup new site"
132
+ def new(aGitUrl,aPath=nil)
133
+ aPath ||= File.basename(aGitUrl,'.git')
134
+ init(
135
+ aPath,
136
+ git_url: aGitUrl
137
+ )
138
+ FileUtils.mkdir_p(site_dir)
139
+ FileUtils.mkdir_p(File.join(site_dir,'releases'))
140
+ FileUtils.mkdir_p(File.join(site_dir,'shared'))
141
+
142
+ #+ create rigup.yml if doesn't exist, including option values
143
+ context.config.to_hash.filter_exclude(:site_dir).to_yaml.to_file(File.join(site_dir,'rigup.yml'))
144
+ end
145
+
146
+ desc "deploy [PATH]", "deploy the given site"
147
+ def deploy(aPath=nil)
148
+ init(aPath)
149
+ update_cache
150
+ release
151
+ call_release_command(:install) # call install_command if defined eg. defaults to "thor deploy:install" eg. make changes to files
152
+ call_release_command(:block)
153
+ link_live
154
+ call_release_command(:restart) # call restart_command, defaults to "thor deploy:restart" eg. restart passenger
155
+ call_release_command(:unblock)
156
+ cleanup
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,22 @@
1
+ module Rigup
2
+
3
+ class Config < Buzztools::Config
4
+
5
+ DEFAULTS = {
6
+ site_dir: String,
7
+ git_url: String,
8
+ branch: String,
9
+ commit: String,
10
+ stage: 'live', # or 'staging' or 'development'
11
+ block_command: nil,
12
+ install_command: 'thor deploy:install',
13
+ restart_command: 'thor deploy:restart',
14
+ unblock_command: nil,
15
+ }
16
+
17
+ def initialize(aValues=nil)
18
+ super(DEFAULTS,aValues)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,59 @@
1
+ module Rigup
2
+ class Context
3
+
4
+ attr_reader :config, :options, :argv, :env, :stdout, :stdin, :stderr, :key_chain, :credentials, :logger, :pwd, :variant
5
+ attr_writer :pwd
6
+
7
+ def sudo
8
+ ''
9
+ end
10
+
11
+ def initialize(aValues=nil)
12
+ return if !aValues
13
+
14
+ #is_client = !!(aValues[:key_chain] || aValues[:global_options] || aValues[:options])
15
+ @config = aValues[:config]
16
+ @pwd = Buzztools::File.real_path(aValues[:pwd] || (@config && @config[:folder]) || Dir.pwd)
17
+ @options = aValues[:options]
18
+ @argv = aValues[:argv]
19
+ @env = aValues[:env]
20
+ @stdout = aValues[:stdout]
21
+ @stdin = aValues[:stdin]
22
+ @stderr = aValues[:stderr]
23
+ @key_chain = aValues[:key_chain]
24
+ @credentials = aValues[:credentials]
25
+ @logger = aValues[:logger]
26
+ @variant = aValues[:variant]
27
+ end
28
+
29
+ def git_root
30
+ @git_root ||= find_git_root
31
+ end
32
+
33
+ # http://thinkingdigitally.com/archive/capturing-output-from-puts-in-ruby/
34
+ #class SimpleSemParserTest < Test::Unit::TestCase
35
+ # def test_set_stmt_write
36
+ # out = capture_stdout do
37
+ # parser = SimpleSemParser.new
38
+ # parser.parse('set write, "Hello World!"').execute
39
+ # end
40
+ # assert_equal "Hello World!\n", out.string
41
+ # end
42
+ #end
43
+ def capture_stdout
44
+ stdout_before = @stdout
45
+ out = StringIO.new
46
+ @stdout = out
47
+ yield
48
+ return out.string
49
+ ensure
50
+ @stdout = stdout_before
51
+ end
52
+
53
+ def find_git_root
54
+ git_folder = BuzzTools::File.find_upwards(@pwd,'.git')
55
+ return git_folder && git_folder.chomp('/.git')
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ module Rigup
2
+
3
+ class DeployBase < Thor
4
+
5
+ include Rigup::Runability
6
+ include Rigup::InstallUtils
7
+
8
+ no_commands do
9
+ def initialize(*args)
10
+ super
11
+ @release_path = Dir.pwd
12
+ @site_dir = File.expand_path('../..')
13
+ @shared_path = File.expand_path('shared',@site_dir)
14
+ config = {}
15
+ if File.exists?(f=File.join(@release_path,'rigup.yml'))
16
+ file_config = YAML.load(String.from_file(f))
17
+ config.merge!(file_config)
18
+ end
19
+ @context = Rigup::Context.new(
20
+ config: Rigup::Config.new(config),
21
+ logger: ::Logger.new(STDOUT),
22
+ pwd: Dir.pwd,
23
+ )
24
+ end
25
+
26
+ def config
27
+ @context.config
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,148 @@
1
+ require 'git'
2
+
3
+ module Rigup
4
+ class GitRepo
5
+
6
+ include Rigup::Runability
7
+
8
+ attr_reader :git,:configured
9
+
10
+ GIT_METHODS = [:commit,:add,:reset_hard,:path,:clone,:log,:size,:branches,:status,:remotes,:pull,:fetch,:push,:merge]
11
+
12
+ def initialize(aContext=nil)
13
+ @context = (aContext || Rigup::Context.new)
14
+ end
15
+
16
+ def method_missing(sym, *args, &block)
17
+ if @git && GIT_METHODS.include?(sym)
18
+ @git.send sym, *args, &block
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def open(aPath)
25
+ @git = ::Git.open(aPath)
26
+ end
27
+
28
+ def init(*args)
29
+ @git = ::Git.init(*args)
30
+ end
31
+
32
+ def clone(aUrl,aPath)
33
+ @git = ::Git::clone(aUrl,aPath)
34
+ end
35
+
36
+ def open?
37
+ !!@git
38
+ end
39
+
40
+ def empty?
41
+ !@git.branches[0]
42
+ end
43
+
44
+ def status
45
+ result = @git.lib.command_lines('status',['--porcelain'])
46
+ result
47
+ end
48
+
49
+ def changes?
50
+ raise RuntimeError.new('Repository must be open') unless open?
51
+ status.length > 0
52
+ end
53
+
54
+ def commit_all(*args)
55
+ result = begin
56
+ @git.commit_all(*args)
57
+ rescue ::Git::GitExecuteError => e
58
+ if e.message.index("nothing to commit (working directory clean)")
59
+ nil
60
+ else
61
+ raise e
62
+ end
63
+ end
64
+ result = commitFromString(result)
65
+ result
66
+ end
67
+
68
+ # "[master (root-commit) 6bdd9e1] first commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file1.txt"
69
+ def commitFromString(aString)
70
+ return nil if !aString || aString.empty?
71
+ sha = aString.scan(/ ([a-f0-9]+)\]/).flatten.first
72
+ @git.gcommit(sha)
73
+ end
74
+
75
+ def path
76
+ @git.dir.path
77
+ end
78
+
79
+ def origin
80
+ @git.remotes.find {|r| r.name=='origin'}
81
+ end
82
+
83
+ def url
84
+ (o = origin) && o.url
85
+ end
86
+
87
+ def checkout(commit=nil,branch=nil)
88
+ specific_commit = !!commit && !commit.index('HEAD')
89
+ if specific_commit
90
+ @git.checkout commit
91
+ else
92
+ branch ||= 'master'
93
+ @git.checkout(branch)
94
+ end
95
+ end
96
+
97
+ # http://stackoverflow.com/questions/2866358/git-checkout-only-files-without-repository
98
+ # http://www.clientcide.com/best-practices/exporting-files-from-git-similar-to-svn-export/
99
+ def export(aDest)
100
+ #rsync --exclude=.git /source/directory/ user@remote-server.com:/target-directory
101
+ FileUtils.cp_r(path,aDest)
102
+ FileUtils.rm_rf(File.expand_path('.git',aDest))
103
+ end
104
+
105
+ def branch
106
+ @git.current_branch
107
+ end
108
+
109
+ def sha
110
+ head.sha
111
+ end
112
+
113
+ def head
114
+ @git.log.first
115
+ end
116
+
117
+ # ::Git --no-pager diff --name-status 26bb87c3981 191d64820f2b
118
+ # result is array of paths prefixed with status letter then a tab
119
+ # see http://git-scm.com/docs/git-diff under --diff-filter=
120
+ # Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, ...) changed (T)
121
+ def changesBetweenCommits(aFromCommit, aToCommit)
122
+ @git.lib.command_lines('diff',['--name-status',aFromCommit,aToCommit])
123
+ end
124
+
125
+ # Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, ...) changed (T)
126
+ def self.convertChangesToUploadsDeletes(changes)
127
+ uploads = []
128
+ deletes = []
129
+ changes.each do |line|
130
+ continue if line==""
131
+ tabi = line.index("\t")
132
+ status = line[0,tabi]
133
+ path = line[tabi+1..-1]
134
+ if status.index('D')
135
+ deletes << path
136
+ else
137
+ uploads << path
138
+ end
139
+ end
140
+ return uploads,deletes
141
+ end
142
+
143
+ def get_file_content(aPath,aCommitOrBranch=nil)
144
+ @git.lib.command('show',[[aCommitOrBranch||'master',aPath].join(':')]) rescue nil
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,94 @@
1
+ module Rigup
2
+ module InstallUtils
3
+
4
+ def select_suffixed_file(aFile,aExtendedExtension=false)
5
+ ext = Buzztools::File.extension(aFile,aExtendedExtension)
6
+ no_ext = Buzztools::File.no_extension(aFile,aExtendedExtension)
7
+ dir = File.dirname(aFile)
8
+ run "#{@context.sudo} mv -f #{no_ext}.#{@context.config[:stage]}.#{ext} #{aFile}"
9
+ run "#{@context.sudo} rm -f #{no_ext}.*.#{ext}"
10
+ end
11
+
12
+ # Especially for modifiying behaviour eg. of FCKEditor without upsetting the standard files
13
+ # eg. create a public_override folder that duplicates the same structure as public,
14
+ # and contains the modified files. On deployment call
15
+ # override_folder("#{@release_path}/public") # equiv to override_folder("#{@release_path}/public", "#{@release_path}/public_override")
16
+ # and the files in public_override will be copied over public, then public_override removed
17
+ def override_folder(aFolder,aOverrideFolder=nil,aRemove=true)
18
+ aFolder = aFolder.desuffix('/')
19
+ aOverrideFolder ||= (aFolder+'_override')
20
+ run "#{@context.sudo} cp -vrf #{aOverrideFolder}/* #{aFolder}/"
21
+ run "#{@context.sudo} rm -rf #{aOverrideFolder}" if aRemove
22
+ end
23
+
24
+
25
+ # set standard permissions for web sites - readonly for apache user
26
+ def permissions_for_web(aPath,aUser=nil,aGroup=nil,aHideScm=nil)
27
+ aUser ||= @user
28
+ aGroup ||= @group
29
+
30
+ run "#{@context.sudo} chown -R #{aUser}:#{aGroup} #{aPath.ensure_suffix('/')}"
31
+ run_for_all("chmod 755",aPath,:dirs) # !!! perhaps reduce other permissions
32
+ run_for_all("chmod 644",aPath,:files)
33
+ run_for_all("chmod g+s",aPath,:dirs)
34
+ case aHideScm
35
+ when :svn then run_for_all("chmod -R 700",aPath,:dirs,"*/.svn")
36
+ end
37
+ end
38
+
39
+ # run this after permissions_for_web() on dirs that need to be writable by group (apache)
40
+ def permissions_for_web_writable(aPath)
41
+ run "chmod -R g+w #{aPath.ensure_suffix('/')}"
42
+ run_for_all("chmod -R 700",aPath,:dirs,"*/.svn")
43
+ end
44
+
45
+ def internal_permissions(aPath,aKind)
46
+ case aKind
47
+ when 'rails' then
48
+ permissions_for_web(aPath,@user,@group,true)
49
+
50
+ run_for_all("chmod +x",File.join(aPath,'script'),:files)
51
+
52
+
53
+ uploads = @shared_path+'/uploads'
54
+ make_public_cache_dir(uploads)
55
+ #if File.exists?(uploads)
56
+ # permissions_for_web(uploads,@user,@group,true)
57
+ # permissions_for_web_writable(uploads)
58
+ #end
59
+ #permissions_for_web_writable("#{aPath}/tmp")
60
+ make_public_cache_dir("#{aPath}/tmp")
61
+
62
+ run "#{@context.sudo} chown #{@apache_user} #{aPath}/config/environment.rb" unless DEV_MODE # very important for passenger, which uses the owner of this file to run as
63
+
64
+ when 'spree' then
65
+ internal_permissions(aPath,'rails')
66
+ when 'browsercms' then
67
+ internal_permissions(aPath,'rails')
68
+ end
69
+ end
70
+
71
+ def apply_permissions(aPath=nil,aKind=nil)
72
+ aPath ||= @release_path
73
+ aKind ||= @kind || 'rails'
74
+ internal_permissions(aPath, aKind)
75
+ end
76
+
77
+ def ensure_link(aTo,aFrom) #,aDir=nil,aUserGroup=nil,aSudo='')
78
+ raise "Must supply from" if !aFrom
79
+ cmd = []
80
+ #cmd << "cd #{aDir}" if aDir
81
+ cmd << "#{@context.sudo} rm -rf #{aFrom}"
82
+ cmd << "#{@context.sudo} ln -sf #{aTo} #{aFrom}"
83
+ #cmd << "#{@context.sudo} chown -h #{aUserGroup} #{aFrom}" if aUserGroup
84
+ run cmd.join(' && ')
85
+ end
86
+
87
+ def make_public_cache_dir(aStartPath)
88
+ run "#{@context.sudo} mkdir -p #{aStartPath}"
89
+ permissions_for_web(aStartPath)
90
+ permissions_for_web_writable(aStartPath)
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,32 @@
1
+ module Rigup
2
+ module Runability
3
+
4
+ def run(aCommand,aDir=nil)
5
+ @context.logger.debug aCommand
6
+ response = ::POpen4::shell(aCommand,aDir || @context.pwd)
7
+ raise Error, "Command Failed" unless (response && response[:exitcode]==0)
8
+ return response[:stdout]
9
+ end
10
+
11
+ def run_for_all(aCommand,aPath,aFilesOrDirs,aPattern=nil,aInvertPattern=false,aSudo=false)
12
+ #run "#{sudo} find . -wholename '*/.svn' -prune -o -type d -print0 |xargs -0 #{sudo} chmod 750"
13
+ #sudo find . -type f -exec echo {} \;
14
+ cmd = []
15
+ cmd << "sudo" if aSudo
16
+ cmd << "find #{aPath.ensure_suffix('/')}"
17
+ cmd << "-wholename '#{aPattern}'" if aPattern
18
+ cmd << "-prune -o" if aInvertPattern
19
+ cmd << case aFilesOrDirs.to_s[0,1]
20
+ when 'f' then '-type f'
21
+ when 'd' then '-type d'
22
+ else ''
23
+ end
24
+ cmd << "-exec"
25
+ cmd << aCommand
26
+ cmd << "'{}' \\;"
27
+ cmd = cmd.join(' ')
28
+ run cmd
29
+ end
30
+
31
+ end
32
+ end
data/lib/rigup/svn.rb ADDED
@@ -0,0 +1,80 @@
1
+ module Rigup
2
+ module Svn
3
+
4
+ def svnInfo(aPath)
5
+ cmdresult = run "svn info \"#{aPath}\""
6
+ cmdresult = cmdresult.split("\n")
7
+ result = {}
8
+ cmdresult.each do |line|
9
+ parts = line.split(': ')
10
+ next if parts.length!=2 || !parts[0] || !parts[1]
11
+ result[parts[0]] = parts[1]
12
+ end
13
+
14
+ if (url = result['URL']) && (root = result['Repository Root']) && url.start_with?(root)
15
+ result['Short URL'] = url[root.length]
16
+ end
17
+ result
18
+ end
19
+
20
+ def svnCmd(aCommand,aSourceServer,aSourceUrl,aDestPath,aOptions = null)
21
+ "svn #{aCommand} \"#{aSourceServer ? File.join(aSourceServer,aSourceUrl) : aSourceUrl}\" \"#{aDestPath}\" #{aOptions || ''}"
22
+ end
23
+
24
+ def svnCheckoutCmd(aConfig,aCommmand='checkout',aOptions=nil)
25
+ options = []
26
+ options << aOptions if aOptions
27
+ options << '--username '+aConfig['vcs_username'] if aConfig['vcs_username']
28
+ options << '--password '+aConfig['vcs_password'] if aConfig['vcs_password']
29
+ options << '--revision '+aConfig['revision'] if aConfig['revision']
30
+ options = options.join ' '
31
+
32
+ rep = aConfig['repository'].to_s.chomp('/').to_nil
33
+ if rep && (branch = aConfig['branch'])
34
+ branch = '/'+branch unless branch.start_with? '/'
35
+ url = File.join(branch,aConfig['source'].to_s) if aConfig['source']
36
+ else
37
+ url = aConfig['source']
38
+ end
39
+ url = url.chomp('/')
40
+
41
+ svnCmd(aCommmand,rep,url,aConfig['destination'],options)
42
+ end
43
+
44
+ def createSvnConfig(aMergeOptions = nil)
45
+ result = {
46
+ 'repository' => @repository,
47
+ 'source' => @vcs_app_path,
48
+ 'branch' => @branch,
49
+ 'destination' => @release_path,
50
+ 'revision' => @revision
51
+ }
52
+ result.merge!(aMergeOptions) if aMergeOptions
53
+ result
54
+ end
55
+
56
+ def folderIsSvn(aPath)
57
+ return false unless File.exists?(aPath)
58
+ info = svnInfo(aPath)
59
+ return !!(info && info['URL'])
60
+ end
61
+
62
+ # ensure cache_path is an svn repo and is up to date. Checkout if not
63
+ def ensureSvnCacheUpdate(cache_path,svnConfig)
64
+ svnConfig = svnConfig.merge('destination' => cache_path)
65
+ if File.exists?(cache_path)
66
+ raise Error('Dir exists but not a svn folder') unless folderIsSvn(cache_path)
67
+ run "svn revert --non-interactive --recursive \"#{cache_path}\""
68
+ run svnCheckoutCmd(
69
+ svnConfig,
70
+ 'switch',
71
+ '--non-interactive'
72
+ )
73
+ else
74
+ MiscUtils.mkdir?(MiscUtils.path_parent(cache_path))
75
+ run svnCheckoutCmd(svnConfig,'checkout','--non-interactive')
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module Rigup
2
+ VERSION = "0.0.2"
3
+ end
data/lib/rigup.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'thor'
2
+ require 'buzztools'
3
+ require 'logger'
4
+ require 'yaml'
5
+ require 'buzztools/extras/shell_extras'
6
+
7
+ require_relative "rigup/version"
8
+ require_relative "rigup/config"
9
+ require_relative "rigup/context"
10
+ require_relative "rigup/runability"
11
+ require_relative "rigup/install_utils"
12
+ require_relative "rigup/git_repo"
13
+ require_relative "rigup/cli"
14
+ require_relative "rigup/deploy_base"
data/notes.txt ADDED
@@ -0,0 +1,19 @@
1
+ From site root :
2
+
3
+ > cd /var/www
4
+ > rigup new repo_url mysite
5
+ + make dir mysite
6
+ + create rigup.yml if doesn't exist, including option values
7
+ + make dir mysite/releases
8
+ + make dir mysite/shared
9
+
10
+ > rigup deploy mysite
11
+
12
+ + git clone repo_url mysite/releases/20140328234123
13
+ + installing
14
+
15
+
16
+ > cd mysite
17
+ > rigup update
18
+ + using plan rigup.yml
19
+
data/rigup.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rigup/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rigup"
7
+ s.version = Rigup::VERSION
8
+ s.authors = ["Gary McGhee"]
9
+ s.email = ["contact@buzzware.com.au"]
10
+ s.homepage = "http://github.com/buzzware/rigup"
11
+ s.summary = "Toolset for deployment"
12
+ s.description = s.summary
13
+
14
+ ignores = File.readlines(".gitignore").grep(/\S+/).map {|line| line.chomp }
15
+ dotfiles = [".gitignore"]
16
+ s.files = Dir["**/*"].reject {|f| File.directory?(f) || ignores.any? {|i| File.fnmatch(i, f) } } + dotfiles
17
+ s.bindir = 'bin'
18
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
+
21
+ s.add_dependency 'bundler', '~>1.5.3'
22
+ s.add_dependency 'thor', '~> 0.19.1'
23
+
24
+
25
+ s.add_development_dependency 'rspec', '~>2.14.0'
26
+ #s.add_development_dependency('rspec')
27
+
28
+ s.add_development_dependency('rake')
29
+ #s.add_development_dependency('rspec-core')
30
+ #s.add_development_dependency('rdoc')
31
+ #s.add_development_dependency('aruba')
32
+ #s.add_development_dependency('debugger')
33
+ #s.add_runtime_dependency('gli','2.5.0')
34
+ #s.add_runtime_dependency('termios')
35
+ #s.add_runtime_dependency('highline')
36
+ s.add_runtime_dependency('git')
37
+ #s.add_runtime_dependency('middleman')
38
+ s.add_runtime_dependency('buzztools')
39
+ s.add_runtime_dependency('POpen4')
40
+ # https://github.com/geemus/formatador
41
+ #s.add_runtime_dependency('bitbucket_rest_api')
42
+ #s.add_runtime_dependency('osx_keychain')
43
+ #s.add_runtime_dependency('json')
44
+ #s.add_runtime_dependency('net_dav')
45
+ #s.add_runtime_dependency('net-ssh')
46
+ #s.add_runtime_dependency('system_timer')
47
+ end
data/rigup.iml ADDED
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="DBNavigator.Module.ConnectionManager">
4
+ <connections />
5
+ </component>
6
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
7
+ <exclude-output />
8
+ <content url="file://$MODULE_DIR$">
9
+ <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
10
+ </content>
11
+ <orderEntry type="inheritedJdk" />
12
+ <orderEntry type="sourceFolder" forTests="false" />
13
+ <orderEntry type="library" scope="PROVIDED" name="POpen4 (v0.1.4, RVM: ruby-2.0.0-p247) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="Platform (v0.4.0, RVM: ruby-2.0.0-p247) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v1.5.3, RVM: ruby-2.0.0-p247) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="buzztools (v0.0.4, RVM: ruby-2.0.0-p247) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.2.5, RVM: ruby-2.0.0-p247) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="git (v1.2.6, RVM: ruby-2.0.0-p247) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="open4 (v1.3.3, RVM: ruby-2.0.0-p247) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.2.0, RVM: ruby-2.0.0-p247) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="rspec (v2.14.1, RVM: ruby-2.0.0-p247) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="rspec-core (v2.14.8, RVM: ruby-2.0.0-p247) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v2.14.5, RVM: ruby-2.0.0-p247) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v2.14.6, RVM: ruby-2.0.0-p247) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="thor (v0.19.1, RVM: ruby-2.0.0-p247) [gem]" level="application" />
26
+ </component>
27
+ </module>
28
+
data/spec/new_spec.rb ADDED
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ #require 'file_utils'
3
+
4
+ describe 'rigup' do
5
+
6
+ before :each do
7
+ @old_dir = Dir.pwd
8
+ Dir.chdir(@dir = Dir.mktmpdir("new_spec"))
9
+ end
10
+
11
+ after :each do
12
+ Dir.chdir(@old_dir)
13
+ end
14
+
15
+ def new_site_process(aGitUrl)
16
+ @script = Rigup::Cli.new
17
+ @script.invoke(:new, [aGitUrl, 'mysite'])
18
+ Dir.exists?('mysite/releases').should be
19
+ Dir.exists?('mysite/shared').should be
20
+ File.exists?('mysite/rigup.yml').should be
21
+
22
+ @config = YAML.load_file('mysite/rigup.yml')
23
+ @config[:git_url].should == aGitUrl
24
+ end
25
+
26
+ def mock_get_repo(aUrl,aPath)
27
+ basename = File.basename(aUrl,'.git')
28
+ src = "~/repos/underscore_plus" unless File.exists?(src = "~/repos/#{basename}")
29
+ FileUtils.cp_r(File.expand_path(src),File.expand_path(aPath))
30
+ end
31
+
32
+ def stub_out_github
33
+ ::Rigup::GitRepo.any_instance.stub(:clone) do |aUrl,aPath|
34
+ mock_get_repo(aUrl,aPath)
35
+ end
36
+ end
37
+
38
+ RELEASE_INSTALL = <<-EOS
39
+ class Deploy < Thor
40
+
41
+ desc 'install','install the freshly delivered files'
42
+ def install
43
+ puts 'install'
44
+ end
45
+
46
+ desc 'restart','restart the web server'
47
+ def restart
48
+ puts 'restart'
49
+ end
50
+
51
+ end
52
+ EOS
53
+
54
+ describe "Given new project" do
55
+
56
+ it "deploy should update_cache, install and link_live" do
57
+ #Rigup::Cli.any_instance.stub(:restart => true, :install => true)
58
+ new_site_process('https://github.com/buzzware/underscore_plus.git')
59
+ ::Rigup::GitRepo.any_instance.stub(:clone) do |aUrl,aPath|
60
+ mock_get_repo(aUrl,aPath)
61
+ RELEASE_INSTALL.to_file(File.join(aPath,'deploy.thor'))
62
+ end
63
+
64
+ @script2 = Rigup::Cli.new
65
+ @script2.invoke(:deploy, ['mysite'])
66
+
67
+ Dir.exists?('mysite/shared/cached-copy').should be
68
+ Dir.exists?('mysite/shared/cached-copy/.git').should be
69
+ Dir.exists?('mysite/shared/cached-copy/.git').should be
70
+
71
+ Dir.exists?('mysite/current').should be
72
+
73
+ entries = Dir.entries('mysite/releases')
74
+ entries.length.should == 3
75
+ release_path = entries.last
76
+ release_path.should =~ /#{Time.now.strftime('%Y%m%d%H')}/
77
+
78
+ # Release method should write a rigup.yml including branch, commit, stage etc (should not be in repo)
79
+ # Rigup::DeployBase then reads this and makes it accessible to install and restart methods
80
+ # Then we can do things like displaying git commit hash on page as the site knows its own full identity
81
+ release_config = YAML.load_file("mysite/releases/#{release_path}/rigup.yml")
82
+ release_config.should be_a Hash
83
+
84
+ cache_repo = ::Rigup::GitRepo.new(Rigup::Context.new)
85
+ cache_repo.open('mysite/shared/cached-copy')
86
+
87
+ release_config[:branch].should be
88
+ release_config[:branch].should == cache_repo.branch
89
+ release_config[:commit].should be
90
+ release_config[:commit].should == cache_repo.sha
91
+ release_config[:stage].should == 'live'
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'rspec'
4
+ require 'rigup'
5
+ require_relative 'spec_utils'
6
+
7
+ include Rigup
8
+
9
+ #RSpec.configure do |config|
10
+ # def config.escaped_path(*parts)
11
+ # Regexp.compile(parts.join('[\\\/]'))
12
+ # end unless config.respond_to? :escaped_path
13
+ #end
14
+
15
+ # Include support files.
16
+ #Dir["#{File.expand_path('../', __FILE__)}/support/**/*.rb"].each { |f| require f }
File without changes
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rigup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Gary McGhee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.19.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.19.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: git
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: buzztools
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: POpen4
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Toolset for deployment
112
+ email:
113
+ - contact@buzzware.com.au
114
+ executables:
115
+ - rigup
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - bin/rigup
120
+ - example deploy.thor
121
+ - Gemfile
122
+ - lib/rigup/cli.rb
123
+ - lib/rigup/config.rb
124
+ - lib/rigup/context.rb
125
+ - lib/rigup/deploy_base.rb
126
+ - lib/rigup/git_repo.rb
127
+ - lib/rigup/install_utils.rb
128
+ - lib/rigup/runability.rb
129
+ - lib/rigup/svn.rb
130
+ - lib/rigup/version.rb
131
+ - lib/rigup.rb
132
+ - notes.txt
133
+ - Rakefile
134
+ - README.md
135
+ - rigup.gemspec
136
+ - rigup.iml
137
+ - spec/new_spec.rb
138
+ - spec/spec_helper.rb
139
+ - spec/spec_utils.rb
140
+ - .gitignore
141
+ homepage: http://github.com/buzzware/rigup
142
+ licenses: []
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.1.5
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Toolset for deployment
164
+ test_files:
165
+ - spec/new_spec.rb
166
+ - spec/spec_helper.rb
167
+ - spec/spec_utils.rb