roger 0.0.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +2 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +102 -0
- data/Gemfile +5 -0
- data/MIT_LICENSE +20 -0
- data/README.md +10 -10
- data/Rakefile +9 -0
- data/bin/roger +5 -0
- data/doc/cli.md +46 -0
- data/doc/mockupfile.md +3 -0
- data/doc/templating.md +88 -0
- data/examples/default_template/.gitignore +2 -0
- data/examples/default_template/CHANGELOG +0 -0
- data/examples/default_template/Gemfile +3 -0
- data/examples/default_template/Mockupfile +1 -0
- data/examples/default_template/html/.empty_directory +0 -0
- data/examples/default_template/partials/.empty_directory +0 -0
- data/lib/roger/cli/command.rb +23 -0
- data/lib/roger/cli/generate.rb +5 -0
- data/lib/roger/cli/release.rb +10 -0
- data/lib/roger/cli/serve.rb +29 -0
- data/lib/roger/cli.rb +123 -0
- data/lib/roger/extractor.rb +95 -0
- data/lib/roger/generators/generator.rb +23 -0
- data/lib/roger/generators/new.rb +67 -0
- data/lib/roger/generators/templates/generator.tt +13 -0
- data/lib/roger/generators.rb +23 -0
- data/lib/roger/mockupfile.rb +63 -0
- data/lib/roger/project.rb +92 -0
- data/lib/roger/rack/html_validator.rb +26 -0
- data/lib/roger/rack/roger.rb +52 -0
- data/lib/roger/rack/sleep.rb +21 -0
- data/lib/roger/release/cleaner.rb +47 -0
- data/lib/roger/release/finalizers/dir.rb +29 -0
- data/lib/roger/release/finalizers/git_branch.rb +92 -0
- data/lib/roger/release/finalizers/rsync.rb +77 -0
- data/lib/roger/release/finalizers/zip.rb +42 -0
- data/lib/roger/release/finalizers.rb +19 -0
- data/lib/roger/release/injector.rb +99 -0
- data/lib/roger/release/processors/mockup.rb +93 -0
- data/lib/roger/release/processors/url_relativizer.rb +45 -0
- data/lib/roger/release/processors.rb +17 -0
- data/lib/roger/release/scm/git.rb +101 -0
- data/lib/roger/release/scm.rb +32 -0
- data/lib/roger/release.rb +363 -0
- data/lib/roger/resolver.rb +119 -0
- data/lib/roger/server.rb +117 -0
- data/lib/roger/template.rb +206 -0
- data/lib/roger/w3c_validator.rb +129 -0
- data/roger.gemspec +35 -0
- data/test/Mockupfile-syntax.rb +85 -0
- data/test/project/.rvmrc +1 -0
- data/test/project/Gemfile +7 -0
- data/test/project/Gemfile.lock +38 -0
- data/test/project/Mockupfile +13 -0
- data/test/project/html/formats/erb.html.erb +5 -0
- data/test/project/html/formats/index.html +1 -0
- data/test/project/html/formats/json.json.erb +0 -0
- data/test/project/html/formats/markdown.md +3 -0
- data/test/project/html/formats/mockup.html +5 -0
- data/test/project/html/front_matter/erb.html.erb +16 -0
- data/test/project/html/front_matter/markdown.md +7 -0
- data/test/project/html/layouts/content-for.html.erb +17 -0
- data/test/project/html/layouts/erb.html.erb +19 -0
- data/test/project/html/mockup/encoding.html +3 -0
- data/test/project/html/partials/erb.html.erb +10 -0
- data/test/project/html/partials/load_path.html.erb +3 -0
- data/test/project/html/partials/mockup.html +13 -0
- data/test/project/html/static/non-relative.html.erb +9 -0
- data/test/project/html/static/relative.html.erb +9 -0
- data/test/project/layouts/test.html.erb +34 -0
- data/test/project/layouts/yield.html.erb +1 -0
- data/test/project/lib/generators/test.rb +9 -0
- data/test/project/partials/formats/erb.html.erb +1 -0
- data/test/project/partials/partials-test.html.erb +1 -0
- data/test/project/partials/test/erb.html.erb +1 -0
- data/test/project/partials/test/front_matter.html.erb +1 -0
- data/test/project/partials/test/json.json.erb +1 -0
- data/test/project/partials/test/markdown.md +1 -0
- data/test/project/partials/test/mockup.part.html +1 -0
- data/test/project/partials/test/simple.html.erb +1 -0
- data/test/project/partials2/partials2-test.html.erb +1 -0
- data/test/unit/cli_test.rb +12 -0
- data/test/unit/generators_test.rb +75 -0
- data/test/unit/release/cleaner_test.rb +47 -0
- data/test/unit/resolver_test.rb +92 -0
- data/test/unit/template_test.rb +127 -0
- metadata +202 -8
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module Roger::Release::Finalizers
|
4
|
+
|
5
|
+
# Finalizes the release by uploading your mockup with rsync to a remote server
|
6
|
+
#
|
7
|
+
# @see RsyncFinalizer#initialize for options
|
8
|
+
#
|
9
|
+
class Rsync < Base
|
10
|
+
|
11
|
+
# @param Hash options The options
|
12
|
+
#
|
13
|
+
# @option options String :rsync The Rsync command to run (default is "rsync")
|
14
|
+
# @option options String :remote_path The remote path to upload to
|
15
|
+
# @option options String :host The remote host to upload to
|
16
|
+
# @option options String :username The remote username to upload to
|
17
|
+
# @option options Boolean :ask Prompt the user before uploading (default is true)
|
18
|
+
def initialize(options = {})
|
19
|
+
@options = {
|
20
|
+
:rsync => "rsync",
|
21
|
+
:remote_path => "",
|
22
|
+
:host => "",
|
23
|
+
:username => "",
|
24
|
+
:ask => true
|
25
|
+
}.update(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(release, options = {})
|
29
|
+
options = @options.dup.update(options)
|
30
|
+
|
31
|
+
# Validate options
|
32
|
+
validate_options!(release, options)
|
33
|
+
|
34
|
+
if !options[:ask] || (prompt("Do you wish to upload to #{options[:host]}? Type y[es]: ")) =~ /\Ay(es)?\Z/
|
35
|
+
begin
|
36
|
+
`#{@options[:rsync]} --version`
|
37
|
+
rescue Errno::ENOENT
|
38
|
+
raise RuntimeError, "Could not find rsync in #{@options[:rsync].inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
local_path = release.build_path.to_s
|
42
|
+
remote_path = options[:remote_path]
|
43
|
+
|
44
|
+
local_path += "/" unless local_path =~ /\/\Z/
|
45
|
+
remote_path += "/" unless remote_path =~ /\/\Z/
|
46
|
+
|
47
|
+
release.log(self, "Starting upload of #{(release.build_path + "*")} to #{options[:host]}")
|
48
|
+
|
49
|
+
command = "#{options[:rsync]} -az #{Shellwords.escape(local_path)} #{Shellwords.escape(options[:username])}@#{Shellwords.escape(options[:host])}:#{Shellwords.escape(remote_path)}"
|
50
|
+
|
51
|
+
# Run r.js optimizer
|
52
|
+
output = `#{command}`
|
53
|
+
|
54
|
+
# Check if r.js succeeded
|
55
|
+
unless $?.success?
|
56
|
+
raise RuntimeError, "Rsync failed.\noutput:\n #{output}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def validate_options!(release, options)
|
64
|
+
must_have_keys = [:remote_path, :host, :username]
|
65
|
+
if (options.keys & must_have_keys).size != must_have_keys.size
|
66
|
+
release.log(self, "You must specify these options: #{(must_have_keys - options.keys).inspect}")
|
67
|
+
raise "Missing keys: #{(must_have_keys - options.keys).inspect}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def prompt(question = 'Do you wish to continue?')
|
72
|
+
print(question)
|
73
|
+
return $stdin.gets.strip
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Roger::Release::Finalizers
|
2
|
+
|
3
|
+
class Zip < Base
|
4
|
+
|
5
|
+
attr_reader :release
|
6
|
+
|
7
|
+
# @option options :prefix Prefix to put before the version (default = "html")
|
8
|
+
# @option options :zip The zip command
|
9
|
+
def call(release, options = {})
|
10
|
+
if options
|
11
|
+
options = @options.dup.update(options)
|
12
|
+
else
|
13
|
+
options = @options
|
14
|
+
end
|
15
|
+
|
16
|
+
options = {
|
17
|
+
:zip => "zip",
|
18
|
+
:prefix => "html"
|
19
|
+
}.update(options)
|
20
|
+
|
21
|
+
name = [options[:prefix], release.scm.version].join("-") + ".zip"
|
22
|
+
release.log(self, "Finalizing release to #{release.target_path + name}")
|
23
|
+
|
24
|
+
if File.exist?(release.target_path + name)
|
25
|
+
release.log(self, "Removing existing target #{release.target_path + name}")
|
26
|
+
FileUtils.rm_rf(release.target_path + name)
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
`#{options[:zip]} -v`
|
31
|
+
rescue Errno::ENOENT
|
32
|
+
raise RuntimeError, "Could not find zip in #{options[:zip].inspect}"
|
33
|
+
end
|
34
|
+
|
35
|
+
::Dir.chdir(release.build_path) do
|
36
|
+
`#{options[:zip]} -r -9 "#{release.target_path + name}" ./*`
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Roger::Release::Finalizers
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = {}
|
6
|
+
@options.update(options) if options
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(release, options = {})
|
10
|
+
raise ArgumentError, "Implement in subclass"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require File.dirname(__FILE__) + "/finalizers/zip"
|
16
|
+
require File.dirname(__FILE__) + "/finalizers/dir"
|
17
|
+
require File.dirname(__FILE__) + "/finalizers/rsync"
|
18
|
+
require File.dirname(__FILE__) + "/finalizers/git_branch"
|
19
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
module Roger
|
3
|
+
|
4
|
+
# Inject VERSION / DATE (i.e. in TOC)
|
5
|
+
# r.inject({"VERSION" => release.version, "DATE" => release.date}, :into => %w{_doc/toc.html})
|
6
|
+
|
7
|
+
# Inject CHANGELOG
|
8
|
+
# r.inject({"CHANGELOG" => {:file => "", :filter => BlueCloth}}, :into => %w{_doc/changelog.html})
|
9
|
+
|
10
|
+
class Release::Injector
|
11
|
+
|
12
|
+
# @example Simple variable injection (replaces [VARIABLE] into all .css files)
|
13
|
+
# {"[VARIABLE]" => "replacement"}, :into => %w{**/*.css}
|
14
|
+
#
|
15
|
+
# @example Regex variable injection (replaces all matches into test.js files)
|
16
|
+
# {/\/\*\s*\[BANNER\]\s*\*\// => "replacement"}, :into => %w{javacripts/test.js}
|
17
|
+
#
|
18
|
+
# @example Simple variable injection with filtering (replaces [VARIABLE] with :content run through the markdown processor into all .html files)
|
19
|
+
# {"[VARIABLE]" => {:content => "# header one", :processor => "md"}, :into => %w{**/*.html}
|
20
|
+
#
|
21
|
+
# @example Full file injection (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG.md" into _doc/changelog.html)
|
22
|
+
#
|
23
|
+
# {"CHANGELOG" => {:file => "CHANGELOG.md"}}, :into => %w{_doc/changelog.html}
|
24
|
+
#
|
25
|
+
# @example Full file injection with filtering (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG" which ran through Markdown compresser into _doc/changelog.html)
|
26
|
+
#
|
27
|
+
# {"CHANGELOG" => {:file => "CHANGELOG", :processor => "md"}}, :into => %w{_doc/changelog.html}
|
28
|
+
#
|
29
|
+
# Processors are based on Tilt (https://github.com/rtomayko/tilt).
|
30
|
+
# Currently supported/tested processors are:
|
31
|
+
#
|
32
|
+
# * 'md' for Markdown (bluecloth)
|
33
|
+
#
|
34
|
+
# Injection files are relative to the :source_path
|
35
|
+
#
|
36
|
+
# @param [Hash] variables Variables to inject. See example for more info
|
37
|
+
# @option options [Array] :into An array of file globs relative to the build_path
|
38
|
+
def initialize(variables, options)
|
39
|
+
@variables = variables
|
40
|
+
@options = options
|
41
|
+
end
|
42
|
+
|
43
|
+
def call(release, options = {})
|
44
|
+
@options.update(options)
|
45
|
+
files = release.get_files(@options[:into])
|
46
|
+
|
47
|
+
files.each do |f|
|
48
|
+
c = File.read(f)
|
49
|
+
injected_vars = []
|
50
|
+
@variables.each do |variable, injection|
|
51
|
+
if c.gsub!(variable, get_content(injection, release))
|
52
|
+
injected_vars << variable
|
53
|
+
end
|
54
|
+
end
|
55
|
+
release.log(self, "Injected variables #{injected_vars.inspect} into #{f}") if injected_vars.size > 0
|
56
|
+
File.open(f,"w") { |fh| fh.write c }
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_content(injection, release)
|
62
|
+
case injection
|
63
|
+
when String
|
64
|
+
injection
|
65
|
+
when Hash
|
66
|
+
get_complex_injection(injection, release)
|
67
|
+
else
|
68
|
+
if injection.respond_to?(:to_s)
|
69
|
+
injection.to_s
|
70
|
+
else
|
71
|
+
raise ArgumentError, "Woah, what's this? #{injection.inspect}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_complex_injection(injection, release)
|
77
|
+
|
78
|
+
if injection[:file]
|
79
|
+
content = File.read(release.source_path + injection[:file])
|
80
|
+
else
|
81
|
+
content = injection[:content]
|
82
|
+
end
|
83
|
+
|
84
|
+
raise ArgumentError, "No :content or :file specified" if !content
|
85
|
+
|
86
|
+
if injection[:processor]
|
87
|
+
if tmpl = Tilt[injection[:processor]]
|
88
|
+
(tmpl.new{ content }).render
|
89
|
+
else
|
90
|
+
raise ArgumentError, "Unknown processor #{injection[:processor]}"
|
91
|
+
end
|
92
|
+
else
|
93
|
+
content
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Roger::Release::Processors
|
2
|
+
class Mockup < Base
|
3
|
+
|
4
|
+
attr_accessor :project
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@options = {
|
8
|
+
:env => {},
|
9
|
+
:match => ["**/*.{html,md,html.erb}"],
|
10
|
+
:skip => [/\Astylesheets/, /\Ajavascripts/]
|
11
|
+
}
|
12
|
+
|
13
|
+
@options.update(options) if options
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(release, options={})
|
17
|
+
self.project = release.project
|
18
|
+
|
19
|
+
options = {}.update(@options).update(options)
|
20
|
+
|
21
|
+
options[:env].update("MOCKUP_PROJECT" => project)
|
22
|
+
|
23
|
+
release.log(self, "Processing mockup files")
|
24
|
+
|
25
|
+
release.log(self, " Matching: #{options[:match].inspect}", true)
|
26
|
+
release.log(self, " Skiping : #{options[:skip].inspect}", true)
|
27
|
+
release.log(self, " Env : #{options[:env].inspect}", true)
|
28
|
+
release.log(self, " Files :", true)
|
29
|
+
|
30
|
+
release.get_files(options[:match], options[:skip]).each do |file_path|
|
31
|
+
release.log(self, " Extract: #{file_path}", true)
|
32
|
+
self.run_on_file!(file_path, options[:env])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def run_on_file!(file_path, env = {})
|
38
|
+
template = Roger::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path)
|
39
|
+
|
40
|
+
# Clean up source file
|
41
|
+
FileUtils.rm(file_path)
|
42
|
+
|
43
|
+
# Write out new file
|
44
|
+
File.open(self.target_path(file_path, template),"w"){|f| f.write(template.render(env.dup)) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Runs the extractor on a single file and return processed source.
|
48
|
+
def extract_source_from_file(file_path, env = {})
|
49
|
+
Roger::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path).render(env.dup)
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def target_path(path, template)
|
55
|
+
# 1. If we have a double extension we rip of the template it's own extension and be done with it
|
56
|
+
parts = File.basename(path.to_s).split(".")
|
57
|
+
dir = Pathname.new(File.dirname(path.to_s))
|
58
|
+
|
59
|
+
# 2. Try to figure out the extension based on the template's mime-type
|
60
|
+
mime_types = {
|
61
|
+
"text/html" => "html",
|
62
|
+
"text/css" => "css",
|
63
|
+
"application/javascript" => "js",
|
64
|
+
"text/xml" => "xml",
|
65
|
+
"application/xml" => "xml",
|
66
|
+
"text/csv" => "csv",
|
67
|
+
"application/json" => "json"
|
68
|
+
}
|
69
|
+
extension = mime_types[template.template.class.default_mime_type]
|
70
|
+
|
71
|
+
# Always return .html directly as it will cause too much trouble otherwise
|
72
|
+
if parts.last == "html"
|
73
|
+
return path
|
74
|
+
end
|
75
|
+
|
76
|
+
if parts.size > 2
|
77
|
+
# Strip extension
|
78
|
+
dir + parts[0..-2].join(".")
|
79
|
+
else
|
80
|
+
return path if extension.nil?
|
81
|
+
|
82
|
+
if parts.size > 1
|
83
|
+
# Strip extension and replace with extension
|
84
|
+
dir + (parts[0..-2] << extension).join(".")
|
85
|
+
else
|
86
|
+
# Let's just add the extension
|
87
|
+
dir + (parts << extension).join(".")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '../../../resolver'
|
2
|
+
|
3
|
+
module Roger::Release::Processors
|
4
|
+
class UrlRelativizer < Base
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@options = {
|
8
|
+
:url_attributes => %w{src href action},
|
9
|
+
:match => ["**/*.html"],
|
10
|
+
:skip => []
|
11
|
+
}
|
12
|
+
|
13
|
+
@options.update(options) if options
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(release, options={})
|
17
|
+
options = {}.update(@options).update(options)
|
18
|
+
|
19
|
+
release.log(self, "Relativizing all URLS in #{options[:match].inspect} files in attributes #{options[:url_attributes].inspect}, skipping #{options[:skip].any? ? options[:skip].inspect : "none" }")
|
20
|
+
|
21
|
+
@resolver = Roger::Resolver.new(release.build_path)
|
22
|
+
release.get_files(options[:match], options[:skip]).each do |file_path|
|
23
|
+
release.debug(self, "Relativizing URLS in #{file_path}") do
|
24
|
+
orig_source = File.read(file_path)
|
25
|
+
File.open(file_path,"w") do |f|
|
26
|
+
doc = Hpricot(orig_source)
|
27
|
+
options[:url_attributes].each do |attribute|
|
28
|
+
(doc/"*[@#{attribute}]").each do |tag|
|
29
|
+
converted_url = @resolver.url_to_relative_url(tag[attribute], file_path)
|
30
|
+
release.debug(self, "Converting '#{tag[attribute]}' to '#{converted_url}'")
|
31
|
+
case converted_url
|
32
|
+
when String
|
33
|
+
tag[attribute] = converted_url
|
34
|
+
when nil
|
35
|
+
release.log(self, "Could not resolve link #{tag[attribute]} in #{file_path}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
f.write(doc.to_original_html)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Roger::Release::Processors
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = {}
|
6
|
+
@options.update(options) if options
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def call(release, options = {})
|
11
|
+
raise ArgumentError, "Implement in subclass"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require File.dirname(__FILE__) + "/processors/mockup"
|
17
|
+
require File.dirname(__FILE__) + "/processors/url_relativizer"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Roger::Release::Scm
|
4
|
+
class Git < Base
|
5
|
+
|
6
|
+
# @option config [String] :ref Ref to use for current tag
|
7
|
+
# @option config [String, Pathname] :path Path to working dir
|
8
|
+
def initialize(config={})
|
9
|
+
super(config)
|
10
|
+
@config[:ref] ||= "HEAD"
|
11
|
+
end
|
12
|
+
|
13
|
+
# Version is either:
|
14
|
+
# - the tagged version number (first "v" will be stripped) or
|
15
|
+
# - the return value of "git describe --tags HEAD"
|
16
|
+
# - the short SHA1 if there hasn't been a previous tag
|
17
|
+
def version
|
18
|
+
get_scm_data if @_version.nil?
|
19
|
+
@_version
|
20
|
+
end
|
21
|
+
|
22
|
+
# Date will be Time.now if it can't be determined from GIT repository
|
23
|
+
def date
|
24
|
+
get_scm_data if @_date.nil?
|
25
|
+
@_date
|
26
|
+
end
|
27
|
+
|
28
|
+
def previous
|
29
|
+
self.class.new(@config.dup.update(:ref => get_previous_tag_name))
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def get_previous_tag_name
|
35
|
+
# Get list of SHA1 that have a ref
|
36
|
+
begin
|
37
|
+
sha1s = `git --git-dir=#{git_dir} log --pretty='%H' --simplify-by-decoration`.split("\n")
|
38
|
+
tags = []
|
39
|
+
while tags.size < 2 && sha1s.any?
|
40
|
+
sha1 = sha1s.shift
|
41
|
+
tag = `git --git-dir=#{git_dir} describe --tags --exact-match #{sha1} 2>/dev/null`.strip
|
42
|
+
tags << tag if !tag.empty?
|
43
|
+
end
|
44
|
+
tags.last
|
45
|
+
rescue
|
46
|
+
raise "Could not get previous tag"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def git_dir
|
51
|
+
@git_dir ||= find_git_dir(@config[:path])
|
52
|
+
end
|
53
|
+
|
54
|
+
# Some hackery to determine if we're on a tagged version or not
|
55
|
+
def get_scm_data(ref = @config[:ref])
|
56
|
+
@_version = ""
|
57
|
+
@_date = Time.now
|
58
|
+
begin
|
59
|
+
if File.exist?(git_dir)
|
60
|
+
@_version = `git --git-dir=#{git_dir} describe --tags #{ref} 2>&1`
|
61
|
+
|
62
|
+
if $?.to_i > 0
|
63
|
+
# HEAD is not a tagged verison, get the short SHA1 instead
|
64
|
+
@_version = `git --git-dir=#{git_dir} show #{ref} --format=format:"%h" -s 2>&1`
|
65
|
+
else
|
66
|
+
# HEAD is a tagged version, if version is prefixed with "v" it will be stripped off
|
67
|
+
@_version.gsub!(/^v/,"")
|
68
|
+
end
|
69
|
+
@_version.strip!
|
70
|
+
|
71
|
+
# Get the date in epoch time
|
72
|
+
date = `git --git-dir=#{git_dir} show #{ref} --format=format:"%ct" -s 2>&1`
|
73
|
+
if date =~ /\d+/
|
74
|
+
@_date = Time.at(date.to_i)
|
75
|
+
else
|
76
|
+
@_date = Time.now
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
rescue RuntimeError => e
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# Find the git dir
|
86
|
+
def find_git_dir(path)
|
87
|
+
path = Pathname.new(path).realpath
|
88
|
+
while path.parent != path && !(path + ".git").directory?
|
89
|
+
path = path.parent
|
90
|
+
end
|
91
|
+
|
92
|
+
path = path + ".git"
|
93
|
+
|
94
|
+
raise "Could not find suitable .git dir in #{path}" if !path.directory?
|
95
|
+
|
96
|
+
path
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Roger::Release::Scm
|
2
|
+
class Base
|
3
|
+
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def initialize(config={})
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the release version string from the SCM
|
11
|
+
#
|
12
|
+
# @return String The current version string
|
13
|
+
def version
|
14
|
+
raise "Implement in subclass"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the release version date from the SCM
|
18
|
+
def date
|
19
|
+
raise "Implement in subclass"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a Release::Scm object with the previous version's data
|
23
|
+
#
|
24
|
+
# @return Roger::Release::Scm The previous version
|
25
|
+
def previous
|
26
|
+
raise "Implement in subclass"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require File.dirname(__FILE__) + "/scm/git"
|