svn_branch 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,8 @@
1
+ == 0.2.1 2007-06-17
2
+
3
+ * Fixed up svn:branch:merge_to_trunk
4
+
5
+ == 0.0.2 2007-06-10
6
+
7
+ * 1 major enhancement:
8
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/svn_branch.rb
6
+ lib/svn_branch/version.rb
7
+ lib/tasks/create.rake
8
+ lib/tasks/merge.rake
9
+ scripts/txt2html
10
+ setup.rb
11
+ test/test_helper.rb
12
+ test/test_svn_branch.rb
13
+ website/index.html
14
+ website/index.txt
15
+ website/javascripts/rounded_corners_lite.inc.js
16
+ website/stylesheets/screen.css
17
+ website/template.rhtml
data/README.txt ADDED
@@ -0,0 +1,6 @@
1
+ README for svn_branch
2
+ =====================
3
+
4
+ A collection of rake tasks to automate the svn functions within a project, with special support for rails projects.
5
+
6
+ For example, the creation of new branch, plus for rails apps, a new database.yml and new databases for development and test, for the branch.
data/Rakefile ADDED
@@ -0,0 +1,95 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'svn_branch', 'version')
13
+
14
+ AUTHOR = 'nicwilliams' # can also be an array of Authors
15
+ EMAIL = "drnicwilliams@gmail.com"
16
+ GEM_NAME = 'svn_branch' # what ppl will type to install your gem
17
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
18
+ RUBYFORGE_USERNAME = config["username"]
19
+ RUBYFORGE_PROJECT = 'drnicutilities' # The unix name for your project
20
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
21
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
22
+
23
+ NAME = "svn_branch"
24
+ REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
25
+ VERS = SvnBranch::VERSION::STRING + (REV ? ".#{REV}" : "")
26
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
27
+ RDOC_OPTS = ['--quiet', '--title', 'svn_branch documentation',
28
+ "--opname", "index.html",
29
+ "--line-numbers",
30
+ "--main", "README",
31
+ "--inline-source"]
32
+
33
+ class Hoe
34
+ def extra_deps
35
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
36
+ end
37
+ end
38
+
39
+ # Generate all the Rake tasks
40
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
41
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
42
+ p.author = AUTHOR
43
+ p.description = p.paragraphs_of("README.txt", 1..1).join("\n\n")
44
+ p.email = EMAIL
45
+ p.summary = p.paragraphs_of("README.txt", 1..2).join("\n\n")
46
+ p.url = HOMEPATH
47
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
48
+ p.test_globs = ["test/**/test_*.rb"]
49
+ p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
50
+
51
+ # == Optional
52
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
53
+ p.extra_deps = [['gemsonrails', '>=0.5.0']] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
54
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
55
+ end
56
+
57
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
58
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "\#{RUBYFORGE_PROJECT}/\#{GEM_NAME}"
59
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
60
+
61
+ desc 'Generate website files'
62
+ task :website_generate do
63
+ Dir['website/**/*.txt'].each do |txt|
64
+ sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
65
+ end
66
+ end
67
+
68
+ desc 'Upload website files to rubyforge'
69
+ task :website_upload do
70
+ host = "#{config["username"]}@rubyforge.org"
71
+ # remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
72
+ remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
73
+ local_dir = 'website'
74
+ sh %{rsync -av #{local_dir}/ #{host}:#{remote_dir}}
75
+ end
76
+
77
+ desc 'Generate and upload website files'
78
+ task :website => [:website_generate, :website_upload]
79
+
80
+ desc 'Release the website and new gem version'
81
+ task :deploy => [:check_version, :website, :release]
82
+
83
+ desc 'Create website and install gem locally'
84
+ task :local_deploy => [:website_generate, :install_gem]
85
+
86
+ task :check_version do
87
+ unless ENV['VERSION']
88
+ puts 'Must pass a VERSION=x.y.z release version'
89
+ exit
90
+ end
91
+ unless ENV['VERSION'] == VERS
92
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
93
+ exit
94
+ end
95
+ end
@@ -0,0 +1,9 @@
1
+ module SvnBranch #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 2
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/svn_branch.rb ADDED
@@ -0,0 +1 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'svn_branch/**/*.rb')].sort.each { |lib| require lib }
@@ -0,0 +1,86 @@
1
+ namespace :svn do
2
+ namespace :branch do
3
+ desc 'Creates a new branch using NAME=branch_name [APP_NAME=app_name]'
4
+ task :create => :environment do
5
+ require 'highline'
6
+
7
+
8
+ puts "Usage: NAME=branch_name" and next unless name = ENV['NAME']
9
+
10
+ svn_info = `svn info`
11
+ puts "Not under svn; ignoring request" and next unless svn_info
12
+ repo_root = (svn_info.match(/^Repository Root:\s(.*)$/) || [nil,nil])[1]
13
+ repo_curr = (svn_info.match(/^URL:\s(.*)$/) || [nil,nil])[1]
14
+ puts "ERROR: cannot find Repository Root via `svn info`" and next unless repo_root
15
+ puts "ERROR: cannot find URL via `svn info`" and next unless repo_curr
16
+ puts "Repository Root: #{repo_root}"
17
+ puts "Checkout URL: #{repo_curr}"
18
+ puts "ERROR: svn project is not setup for branching (needs trunk,branches,tags subfolders)" and next if repo_root == repo_curr
19
+ puts "ERROR: only perform this operation from the trunk checkout" and next if repo_curr.sub(repo_root, '') != '/trunk'
20
+
21
+ app_name = ENV['APP_NAME']
22
+ app_name ||= repo_root.split('/').last
23
+
24
+ curr_path = Dir.pwd
25
+ target_path = File.join(curr_path, '..', "#{app_name}_#{name}")
26
+ repo_branch = File.join(repo_root, 'branches', name)
27
+ puts "Current path: #{curr_path}"
28
+ puts "*Branch path: #{target_path}"
29
+
30
+ puts "*Repos branch: #{repo_branch}"
31
+
32
+ trunk_database_yml = File.read(File.join(curr_path, 'config/database.yml'))
33
+ config = YAML.load(trunk_database_yml)
34
+ adapter = config["development"]["adapter"]
35
+ puts "Adapter: #{adapter}"
36
+
37
+ unless %w[postgresql mysql].include? adapter
38
+ puts "ERROR: Adapter #{adapter} not yet supported. Please ask for it - drnicwilliams@gmail.com"
39
+ next
40
+ end
41
+ question = HighLine.new
42
+ puts "Quitting." and next unless question.agree("Create branch? [y/N]", true)
43
+
44
+ repo_from = repo_curr # TODO allow task to be called from non-trunk to clone branches
45
+ repo_to = repo_branch
46
+ puts `svn copy #{repo_curr} #{repo_to}`
47
+ puts `svn co #{repo_to} #{target_path}`
48
+
49
+ # Now clone the trunk/config/database.yml and gsub(/#{app_name}/,"#{app_name}_#{name}")
50
+ # get database adapter type
51
+ # now create dev + test dbs
52
+ if adapter == 'postgresql'
53
+ createdb = "createdb -E utf8"
54
+ createdb += " --username=#{config["development"]["username"]} --password" if config["development"]["username"]
55
+ elsif adapter == 'mysql'
56
+ createdb = "mysqladmin"
57
+ createdb += " -u #{config["development"]["username"]} " +
58
+ "-p" if config["development"]["username"]
59
+ createdb += " create"
60
+ end
61
+ createdb += " %s"
62
+ %w[development test].each do |db_type|
63
+ db_name = "#{app_name}_#{name}_#{db_type}"
64
+ puts expr = createdb % db_name
65
+ puts `#{expr}`
66
+ end
67
+
68
+ puts "Creating config/database.yml from existing version..."
69
+ File.open(File.join(target_path, "config/database.yml"),'w') do |f|
70
+ f.write(trunk_database_yml.gsub(/database:\s+#{app_name}/,"database: #{app_name}_#{name}"))
71
+ end
72
+
73
+ puts "Creating #{target_path}/log folder if necessary..."
74
+ FileUtils.mkdir_p File.join(target_path, 'log')
75
+
76
+ Dir.chdir target_path do
77
+
78
+ exprs = ["rake db:migrate", "rake db:test:clone", "rake test"]
79
+ exprs.each do |expr|
80
+ puts expr
81
+ puts `#{expr}`
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,72 @@
1
+ namespace :svn do
2
+ namespace :branch do
3
+ desc 'Merges the trunk into this branch'
4
+ task :merge_to_branch do
5
+ require 'highline'
6
+
7
+ # Ideas on merging come from http://svnbook.red-bean.com/en/1.0/ch04s04.html
8
+
9
+ svn_info = `svn info`
10
+ puts "Not under svn; ignoring request" and next unless svn_info
11
+ repo_root = (svn_info.match(/^Repository Root:\s(.*)$/) || [nil,nil])[1]
12
+ repo_curr = (svn_info.match(/^URL:\s(.*)$/) || [nil,nil])[1]
13
+ branch_name = repo_curr.split('/').last
14
+
15
+ repo_trunk = "#{repo_root}/trunk"
16
+ svn_info_trunk = `svn info #{repo_trunk}`
17
+ puts "SVN path #{repo_trunk} does not exist; cannot perform branch - contact Dr Nic" and next unless svn_info_trunk
18
+ unless svn_info_trunk[/Last Changed Rev:\s(\d+)/]
19
+ puts "Cannot find 'Last Changed Rev: xxx' in `svn info #{repo_trunk}`"
20
+ return
21
+ end
22
+ trunk_version = $1.to_i
23
+
24
+ # look in props for previous merge version, else get original branch version
25
+ # or look for rXXX:YYY in log comments, and use that version, e.g. YYY+1
26
+ if `svn log --verbose --stop-on-copy`[/r(\d+)\s/]
27
+ branch_version = $1.to_i
28
+ puts "Branch #{branch_name} created at version #{branch_version}; never merged with trunk yet."
29
+ end
30
+
31
+ puts "Merging changes btw r#{branch_version}:#{trunk_version} from trunk into this branch..."
32
+
33
+ puts merge = "svn merge -r #{branch_version}:#{trunk_version} #{repo_trunk}"
34
+ puts `#{merge}`
35
+
36
+ puts status = "svn status"
37
+ puts `#{status}`
38
+
39
+ puts "1) Now fix up any 'C' conflicts and remove the temporary files"
40
+ puts "2) Fix up your migrations (may need to rollback and put new migrations at the end of the list)"
41
+ puts "3) svn commit -m \"Merged trunk changes into #{branch_name}; r#{branch_version}:#{trunk_version}\""
42
+ end
43
+
44
+ desc 'Merge branch back into trunk; run from trunk'
45
+ task :merge_to_trunk do
46
+ puts "Usage: NAME=branch_name" and next unless name = ENV['NAME']
47
+
48
+ svn_info = `svn info`
49
+ puts "Not under svn; ignoring request" and next unless svn_info
50
+ repo_root = (svn_info.match(/^Repository Root:\s(.*)$/) || [nil,nil])[1]
51
+ repo_curr = (svn_info.match(/^URL:\s(.*)$/) || [nil,nil])[1]
52
+ branch_name = repo_curr.split('/').last
53
+ repo_branch = "#{repo_root}/branches/#{name}"
54
+
55
+ # get the last r(\d+) number
56
+ svn_log = `svn log --verbose --stop-on-copy #{repo_branch}`
57
+ branch_rev = svn_log.scan(/^r(\d+)\s/).last
58
+ # merge branch_rev:HEAD
59
+ puts merge = "svn merge -r #{branch_rev}:HEAD #{repo_branch}"
60
+ puts `#{merge}`
61
+
62
+ # fix conflicts
63
+
64
+ puts "1) Now fix up any 'C' conflicts and remove the temporary files"
65
+ puts "2) Fix up your migrations (may need to increment branch migrations forward)"
66
+ puts "3) rake db:migrate"
67
+ puts "4) rake db:test:clone"
68
+ puts "5) rake"
69
+ puts "6) svn commit -m \"Merged branch changes from #{branch_name}; r#{branch_rev}:HEAD\""
70
+ end
71
+ end
72
+ end
data/scripts/txt2html ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'redcloth'
5
+ require 'syntax/convertors/html'
6
+ require 'erb'
7
+ require File.dirname(__FILE__) + '/../lib/svn_branch/version.rb'
8
+
9
+ version = SvnBranch::VERSION::STRING
10
+ download = 'http://rubyforge.org/projects/svn_branch'
11
+
12
+ class Fixnum
13
+ def ordinal
14
+ # teens
15
+ return 'th' if (10..19).include?(self % 100)
16
+ # others
17
+ case self % 10
18
+ when 1: return 'st'
19
+ when 2: return 'nd'
20
+ when 3: return 'rd'
21
+ else return 'th'
22
+ end
23
+ end
24
+ end
25
+
26
+ class Time
27
+ def pretty
28
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
29
+ end
30
+ end
31
+
32
+ def convert_syntax(syntax, source)
33
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
34
+ end
35
+
36
+ if ARGV.length >= 1
37
+ src, template = ARGV
38
+ template ||= File.dirname(__FILE__) + '/../website/template.rhtml'
39
+
40
+ else
41
+ puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
42
+ exit!
43
+ end
44
+
45
+ template = ERB.new(File.open(template).read)
46
+
47
+ title = nil
48
+ body = nil
49
+ File.open(src) do |fsrc|
50
+ title_text = fsrc.readline
51
+ body_text = fsrc.read
52
+ syntax_items = []
53
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</>!m){
54
+ ident = syntax_items.length
55
+ element, syntax, source = $1, $2, $3
56
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
57
+ "syntax-temp-#{ident}"
58
+ }
59
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
60
+ body = RedCloth.new(body_text).to_html
61
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
62
+ end
63
+ stat = File.stat(src)
64
+ created = stat.ctime
65
+ modified = stat.mtime
66
+
67
+ $stdout << template.result(binding)