vclog 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/HISTORY.rdoc +12 -0
  2. data/README.rdoc +5 -5
  3. data/REQUIRE +1 -0
  4. data/VERSION +2 -2
  5. data/bin/vclog +1 -1
  6. data/features/git.feature +8 -8
  7. data/features/hg.feature +8 -8
  8. data/features/svn.feature +8 -8
  9. data/lib/plugins/syckle/vclog.rb +19 -9
  10. data/lib/vclog/adapters/abstract.rb +78 -9
  11. data/lib/vclog/adapters/darcs.rb +5 -5
  12. data/lib/vclog/adapters.rb +3 -4
  13. data/lib/vclog/change.rb +14 -28
  14. data/lib/vclog/changelog.rb +8 -12
  15. data/lib/vclog/cli/abstract.rb +99 -0
  16. data/lib/vclog/cli/bump.rb +30 -0
  17. data/lib/vclog/cli/changelog.rb +33 -0
  18. data/lib/vclog/cli/help.rb +37 -0
  19. data/lib/vclog/cli/history.rb +40 -0
  20. data/lib/vclog/cli/list.rb +28 -0
  21. data/lib/vclog/cli/version.rb +30 -0
  22. data/lib/vclog/cli.rb +70 -51
  23. data/lib/vclog/config.rb +65 -0
  24. data/lib/vclog/formatter.rb +27 -10
  25. data/lib/vclog/heuristics/default.rb +20 -0
  26. data/lib/vclog/heuristics.rb +86 -8
  27. data/lib/vclog/history.rb +26 -191
  28. data/lib/vclog/kernel.rb +12 -0
  29. data/lib/vclog/metadata.rb +1 -0
  30. data/lib/vclog/release.rb +25 -10
  31. data/lib/vclog/tag.rb +14 -4
  32. data/lib/vclog/templates/changelog.ansi.rb +52 -0
  33. data/lib/vclog/templates/{changelog.atom → changelog.atom.erb} +0 -0
  34. data/lib/vclog/templates/changelog.gnu.rb +31 -0
  35. data/lib/vclog/templates/{changelog.html → changelog.html.erb} +0 -0
  36. data/lib/vclog/templates/changelog.json.rb +1 -0
  37. data/lib/vclog/templates/changelog.markdown.rb +30 -0
  38. data/lib/vclog/templates/changelog.rdoc.rb +30 -0
  39. data/lib/vclog/templates/{changelog.xml → changelog.xml.erb} +0 -0
  40. data/lib/vclog/templates/changelog.yaml.rb +1 -0
  41. data/lib/vclog/templates/history.ansi.rb +59 -0
  42. data/lib/vclog/templates/{history.atom → history.atom.erb} +1 -1
  43. data/lib/vclog/templates/history.gnu.rb +41 -0
  44. data/lib/vclog/templates/history.html.erb +52 -0
  45. data/lib/vclog/templates/history.json.rb +1 -0
  46. data/lib/vclog/templates/history.markdown.rb +40 -0
  47. data/lib/vclog/templates/history.rdoc.rb +40 -0
  48. data/lib/vclog/templates/{history.xml → history.xml.erb} +1 -1
  49. data/lib/vclog/templates/history.yaml.rb +1 -0
  50. data/lib/vclog.rb +6 -1
  51. metadata +95 -21
  52. data/ROADMAP.rdoc +0 -31
  53. data/lib/vclog/templates/changelog.gnu +0 -6
  54. data/lib/vclog/templates/changelog.json +0 -1
  55. data/lib/vclog/templates/changelog.markdown +0 -6
  56. data/lib/vclog/templates/changelog.rdoc +0 -6
  57. data/lib/vclog/templates/changelog.yaml +0 -1
  58. data/lib/vclog/templates/history.gnu +0 -12
  59. data/lib/vclog/templates/history.html +0 -47
  60. data/lib/vclog/templates/history.json +0 -1
  61. data/lib/vclog/templates/history.markdown +0 -12
  62. data/lib/vclog/templates/history.rdoc +0 -12
  63. data/lib/vclog/templates/history.yaml +0 -1
@@ -1,13 +1,91 @@
1
1
  module VCLog
2
2
 
3
- # TODO: Develop heuristics for determining the nature
4
- # of changes from the commit messages. Ultimately allow
5
- # user to customize heuristics per project.
6
- module Heuristics
7
-
8
- def explicit_tag(message)
9
- md = /^(\w+)\:/.match(message)
10
- md ? {:tag => md[1]} : {}
3
+ #
4
+ class Heuristics
5
+
6
+ # Load heuristics from a configruation file.
7
+ #
8
+ # config - the configuration directory
9
+ #
10
+ def self.load(file)
11
+ if file
12
+ raise LoadError unless File.exist?(file)
13
+ else
14
+ file = File.dirname(__FILE__) + '/heuristics/default.rb'
15
+ end
16
+
17
+ h = new
18
+ h.instance_eval(File.read(file), file)
19
+ h
20
+ end
21
+
22
+ #
23
+ def initialize
24
+ @rules = []
25
+ @labels = {}
26
+ end
27
+
28
+ #
29
+ def lookup(message)
30
+ type = nil
31
+ @rules.find{ |rule| type = rule.call(message) }
32
+ if type
33
+ type = type.to_sym
34
+ if @labels.key?(type)
35
+ @labels[type].to_a
36
+ else
37
+ [type, 0, "#{type.to_s.capitalize} Enhancements"]
38
+ end
39
+ else
40
+ [nil, 0, 'General Enhancements']
41
+ end
42
+ end
43
+
44
+ #
45
+ def on(pattern, &block)
46
+ @rules << Rule.new(pattern, &block)
47
+ end
48
+
49
+ #
50
+ def set(type, level, label)
51
+ @labels[type.to_sym] = Label.new(type, level, label)
52
+ end
53
+
54
+ #
55
+ class Label
56
+ #
57
+ def initialize(type, level, label)
58
+ @type = type
59
+ @level = level.to_i
60
+ @label = label.to_s
61
+ end
62
+
63
+ attr :type
64
+
65
+ attr :level
66
+
67
+ attr :label
68
+
69
+ #
70
+ def to_a
71
+ [type, level, label]
72
+ end
73
+ end
74
+
75
+ #
76
+ class Rule
77
+ def initialize(pattern, &block)
78
+ @pattern = pattern
79
+ @block = block
80
+ end
81
+
82
+ def call(message)
83
+ if md = @pattern.match(message)
84
+ @block.call(*md[1..-1])
85
+ else
86
+ nil
87
+ end
88
+ end
11
89
  end
12
90
 
13
91
  end
data/lib/vclog/history.rb CHANGED
@@ -15,13 +15,8 @@ module VCLog
15
15
  # The release version, date and release note can be
16
16
  # descerened from the underlying SCM by identifying
17
17
  # the hard tag commits.
18
- #
19
- # But we can also extract the release information from a
20
- # release history file, if provided. And it's release
21
- # information should take precidence. ???
22
18
  #
23
- #
24
- # TODO: Extract output formating from delta parser.
19
+ # TODO: Extract output formating from delta parser. Later---Huh?
25
20
  #
26
21
  class History
27
22
 
@@ -40,11 +35,15 @@ module VCLog
40
35
  attr_accessor :extra
41
36
 
42
37
  #
43
- def initialize(vcs, opts={})
38
+ def initialize(vcs)
44
39
  @vcs = vcs
45
- @title = opts[:title] || "RELEASE HISTORY"
46
- @extra = opts[:extra]
47
- @version = opts[:version]
40
+
41
+ #opts = OpenStruct.new(opts) if Hash === opts
42
+
43
+ #@title = opts.title || "RELEASE HISTORY"
44
+ #@extra = opts.extra
45
+ #@version = opts.version
46
+ #@level = opts.level || 0
48
47
  end
49
48
 
50
49
  # Tag list from version control system.
@@ -52,31 +51,28 @@ module VCLog
52
51
  @tags ||= vcs.tags
53
52
  end
54
53
 
55
- # Change list from version control system.
56
-
57
- def changes
58
- @changes ||= vcs.changes
59
- end
60
-
61
54
  # Changelog object
62
-
63
55
  def changelog
64
56
  @changlog ||= vcs.changelog #ChangeLog.new(changes)
65
57
  end
66
58
 
67
- #
59
+ # Change list from version control system filter for level setting.
60
+ def changes
61
+ @changes ||= vcs.changes
62
+ end
68
63
 
64
+ #
69
65
  def releases
70
66
  @releases ||= (
71
67
  rel = []
72
68
 
73
69
  tags = self.tags
74
70
 
75
- ver = vcs.bump(version)
71
+ #ver = vcs.bump(version)
76
72
  user = vcs.user
77
73
  time = ::Time.now
78
74
 
79
- tags << Tag.new(ver, 'current', time, user, "Current Development")
75
+ tags << Tag.new(nil, 'current', time, user, "Current Development")
80
76
 
81
77
  # TODO: Do we need to add a Time.now tag?
82
78
  # add current verion to release list (if given)
@@ -88,21 +84,20 @@ module VCLog
88
84
  #rels = rels.uniq # only uniq releases
89
85
 
90
86
  # sort by release date
91
- #tags = tags.sort{ |a,b| b.name <=> a.name }
92
- tags = tags.sort{ |a,b| b.date <=> a.date }
87
+ tags = tags.sort{ |a,b| a.date <=> b.date }
93
88
 
94
89
  # organize into deltas
95
- delta = {}
90
+ delta = []
96
91
  last = nil
97
- tags.sort.each do |tag|
98
- delta[tag] = [last, tag.date]
92
+ tags.each do |tag|
93
+ delta << [tag, [last, tag.date]]
99
94
  last = tag.date
100
95
  end
101
96
 
102
- # gather changes for each delta and build log
103
- delta.each do |tag, (ended, started)|
104
- if ended
105
- set = changes.select{ |c| c.date < ended && c.date > started }
97
+ # gather changes for each delta
98
+ delta.each do |tag, (started, ended)|
99
+ if started
100
+ set = changes.select{ |c| c.date >= started && c.date < ended }
106
101
  #gt_vers, gt_date = gt.name, gt.date
107
102
  #lt_vers, lt_date = lt.name, lt.date
108
103
  #gt_date = Time.parse(gt_date) unless Time===gt_date
@@ -112,7 +107,7 @@ module VCLog
112
107
  #lt_vers, lt_date = lt.name, lt.date
113
108
  #lt_date = Time.parse(lt_date) unless Time===lt_date
114
109
  #log = changelog.before(lt_date)
115
- set = changes.select{ |c| c.date > started }
110
+ set = changes.select{ |c| c.date < ended }
116
111
  end
117
112
 
118
113
  rel << Release.new(tag, set)
@@ -122,9 +117,8 @@ module VCLog
122
117
  end
123
118
 
124
119
  # Group +changes+ by tag type.
125
-
126
120
  def groups(changes)
127
- @groups ||= changes.group_by{ |e| e.type_number }
121
+ @groups ||= changes.group_by{ |e| e.type }
128
122
  end
129
123
 
130
124
  #
@@ -132,165 +126,6 @@ module VCLog
132
126
  releases.map{ |rel| rel.to_h }
133
127
  end
134
128
 
135
-
136
-
137
- # Same as to_gnu.
138
-
139
- #def to_s(rev=false)
140
- # to_gnu(rev)
141
- #end
142
-
143
- =begin
144
- # TODO: What would GNU history look like?
145
-
146
- def to_gnu(rev=false)
147
- to_markdown(rev)
148
- end
149
-
150
- # Translate history into a YAML document.
151
-
152
- def to_yaml(*args)
153
- require 'yaml'
154
- releases.to_yaml(*args)
155
- end
156
-
157
- # Translate history into a JSON document.
158
-
159
- def to_json
160
- require 'json'
161
- releases.to_json
162
- end
163
- =end
164
-
165
- =begin
166
- # Translate history into a XML document.
167
-
168
- def to_xml(xsl=nil)
169
- tmp = File.read(File.join(DIR, 'templates', 'history.xml'))
170
- erb = ERB.new(tmp)
171
- erb.result(binding)
172
- end
173
-
174
- # Translate history into a HTML document.
175
-
176
- def to_html(css=nil)
177
- tmp = File.read(File.join(DIR, 'templates', 'history.html'))
178
- erb = ERB.new(tmp)
179
- erb.result(binding)
180
- end
181
-
182
- # Translate history into a RDoc document.
183
-
184
- def to_rdoc(rev=false)
185
- tmp = File.read(File.join(DIR, 'templates', 'history.rdoc'))
186
- erb = ERB.new(tmp)
187
- erb.result(binding)
188
- end
189
-
190
- # Translate history into a Markdown formatted document.
191
-
192
- def to_markdown(rev=false)
193
- tmp = File.read(File.join(DIR, 'templates', 'history.markdown'))
194
- erb = ERB.new(tmp)
195
- erb.result(binding)
196
- end
197
- =end
198
-
199
- =begin
200
- #
201
- def to_markup(marker, rev=false)
202
- entries = []
203
- releases.each do |release|
204
- tag = release.tag
205
- changes = release.changes
206
- change_text = to_markup_changes(changes, rev)
207
- unless change_text.strip.empty?
208
- if extra
209
- entries << "#{marker*2} #{tag.name} / #{tag.date.strftime('%Y-%m-%d')}\n\n#{tag.message}\n\nChanges:\n\n#{change_text}"
210
- else
211
- entries << "#{marker*2} #{tag.name} / #{tag.date.strftime('%Y-%m-%d')}\n\n#{change_text}"
212
- end
213
- end
214
- end
215
- # reverse entries order and make into document
216
- marker + " #{title}\n\n" + entries.reverse.join("\n")
217
- end
218
- =end
219
-
220
- private
221
-
222
- =begin
223
- #
224
- def to_markup_changes(changes, rev=false)
225
- groups = changes.group_by{ |e| e.type_number }
226
- string = ""
227
- groups.keys.sort.each do |n|
228
- entries = groups[n]
229
- next if !entries
230
- next if entries.empty?
231
- string << "* #{entries.size} #{entries[0].type_phrase}\n\n"
232
- entries.sort!{|a,b| a.date <=> b.date }
233
- entries.each do |entry|
234
- #string << "== #{date} #{who}\n\n" # no email :(
235
- if rev
236
- text = "#{entry.message} (##{entry.revision})"
237
- else
238
- text = "#{entry.message}"
239
- end
240
- text = text.tabto(6)
241
- text[4] = '*'
242
- #entry = entry.join(' ').tabto(6)
243
- #entry[4] = '*'
244
- string << text
245
- string << "\n"
246
- end
247
- string << "\n"
248
- end
249
- string
250
- end
251
- =end
252
-
253
-
254
- =begin
255
- # Extract release tags from a release file.
256
- #
257
- # TODO: need to extract message (?)
258
- #
259
- def releases_from_file(file)
260
- return [] unless file
261
- clog = File.read(file)
262
- tags = clog.scan(/^(==|##)(.*?)$/)
263
- rels = tags.collect do |t|
264
- parse_version_tag(t[1])
265
- end
266
- @marker = tags[0][0]
267
- return rels
268
- end
269
-
270
- #
271
- def parse_version_tag(tag)
272
- version, date = *tag.split('/')
273
- version, date = version.strip, date.strip
274
- return version, date
275
- end
276
- =end
277
-
278
- =begin
279
- private
280
-
281
- #
282
- def h(input)
283
- result = input.to_s.dup
284
- result.gsub!("&", "&amp;")
285
- result.gsub!("<", "&lt;")
286
- result.gsub!(">", "&gt;")
287
- result.gsub!("'", "&apos;")
288
- #result.gsub!("@", "&at;")
289
- result.gsub!("\"", "&quot;")
290
- return result
291
- end
292
- =end
293
-
294
129
  end
295
130
 
296
131
  end
@@ -0,0 +1,12 @@
1
+ module VCLog
2
+
3
+ module Kernel
4
+
5
+ #
6
+ def heuristics
7
+ @heuristics ||= Heuristics.new()
8
+ end
9
+
10
+ end
11
+
12
+ end
@@ -1,5 +1,6 @@
1
1
  module VCLog
2
2
 
3
+ #
3
4
  class Metadata
4
5
 
5
6
  def initialize
data/lib/vclog/release.rb CHANGED
@@ -1,15 +1,39 @@
1
1
  module VCLog
2
2
 
3
- #
3
+ # A Release encapsulate a collection of
4
+ # Change objects associated to a Tag.
4
5
  class Release
6
+
7
+ # Tag object this release represents.
5
8
  attr :tag
9
+
10
+ # Array of Change objects.
6
11
  attr :changes
12
+
13
+ # New Release object.
14
+ #
15
+ # tag - Tag object
16
+ # change - Array of Change objects
7
17
  #
8
18
  def initialize(tag, changes)
9
19
  @tag = tag
10
20
  @changes = changes
11
21
  end
12
22
 
23
+ # Group +changes+ by type and sort by level.
24
+ # Returns an associative array of [type, changes].
25
+ def groups
26
+ @groups ||= (
27
+ changes.group_by{ |e| e.type }.sort{ |a,b| b[1][0].level <=> a[1][0].level }
28
+ )
29
+ end
30
+
31
+ # Compare release by tag.
32
+ def <=>(other)
33
+ @tag <=> other.tag
34
+ end
35
+
36
+ # Convert Release to Hash.
13
37
  def to_h
14
38
  { 'version' => tag.name,
15
39
  'date' => tag.date,
@@ -20,18 +44,9 @@ module VCLog
20
44
  }
21
45
  end
22
46
 
23
- # Group +changes+ by tag type.
24
- def groups
25
- @groups ||= changes.group_by{ |e| e.type_number }
26
- end
27
-
28
47
  #def to_json
29
48
  # to_h.to_json
30
49
  #end
31
-
32
- def <=>(other)
33
- @tag <=> other.tag
34
- end
35
50
  end
36
51
 
37
52
  end
data/lib/vclog/tag.rb CHANGED
@@ -7,6 +7,7 @@ module VCLog
7
7
  attr_accessor :author
8
8
  attr_accessor :message
9
9
 
10
+ #
10
11
  def initialize(name, rev, date, author, message)
11
12
  self.revision = rev
12
13
  self.name = name
@@ -15,15 +16,20 @@ module VCLog
15
16
  self.message = message
16
17
  end
17
18
 
19
+ #
18
20
  def name=(name)
19
- @name = name.strip
21
+ @name = (name || 'HEAD').strip
20
22
  end
23
+
24
+ #
21
25
  alias_method :label, :name
22
26
 
27
+ #
23
28
  def author=(author)
24
29
  @author = author.strip
25
30
  end
26
31
 
32
+ #
27
33
  def date=(date)
28
34
  case date
29
35
  when Time
@@ -33,6 +39,7 @@ module VCLog
33
39
  end
34
40
  end
35
41
 
42
+ #
36
43
  def message=(msg)
37
44
  @message = msg.strip
38
45
  end
@@ -40,15 +47,17 @@ module VCLog
40
47
  alias_method :tagger, :author
41
48
  alias_method :tagger=, :author=
42
49
 
50
+ #
43
51
  def to_json
44
52
  to_h.to_json
45
53
  end
46
54
 
55
+ #
47
56
  def to_h
48
57
  {
49
- 'name' => name,
50
- 'date' => date,
51
- 'author' => author,
58
+ 'name' => name,
59
+ 'date' => date,
60
+ 'author' => author,
52
61
  'message' => message
53
62
  }
54
63
  end
@@ -60,6 +69,7 @@ module VCLog
60
69
 
61
70
  # Normal tag order is the reverse typical sorts.
62
71
  def <=>(other)
72
+ return -1 if name == 'HEAD'
63
73
  other.name <=> name
64
74
  end
65
75
  end
@@ -0,0 +1,52 @@
1
+ require 'ansi'
2
+
3
+ out = []
4
+
5
+ out << "#{title}\n".ansi(:bold) if title
6
+
7
+ changelog.by_date.each do |date, date_changes|
8
+
9
+ date_changes.by_author.each do |author, author_changes|
10
+
11
+ out << "#{ date } #{ author }\n".ansi(:bold)
12
+
13
+ author_changes.sort!{|a,b| b.level <=> a.level}
14
+
15
+ author_changes.each do |entry|
16
+
17
+ line = "#{entry.message.strip}"
18
+
19
+ if options.extra && entry.type
20
+ line << " <#{ entry.type }>"
21
+ end
22
+
23
+ if options.revision
24
+ line << " (##{entry.revision})"
25
+ end
26
+
27
+ case entry.level
28
+ when 1
29
+ line = line.ansi(:yellow)
30
+ when 0
31
+ line = line.ansi(:green)
32
+ when -1
33
+ line = line.ansi(:cyan)
34
+ else
35
+ if entry.level > 1
36
+ line = line.ansi(:red)
37
+ else
38
+ line = line.ansi(:blue)
39
+ end
40
+ end
41
+
42
+ out << " * " + line
43
+
44
+ end
45
+
46
+ out << ""
47
+
48
+ end
49
+
50
+ end
51
+
52
+ out.join("\n") + "\n"
@@ -0,0 +1,31 @@
1
+ out = []
2
+
3
+ out << "#{title}\n" if title
4
+
5
+ changelog.by_date.each do |date, date_changes|
6
+
7
+ date_changes.by_author.each do |author, author_changes|
8
+
9
+ out << "#{ date } #{ author }\n"
10
+
11
+ author_changes.each do |entry|
12
+
13
+ out << " * #{entry.message.strip}"
14
+
15
+ if options.extra && entry.type
16
+ out.last << " <#{ entry.type }>"
17
+ end
18
+
19
+ if options.revision
20
+ out.last << "(##{entry.revision})"
21
+ end
22
+
23
+ end
24
+
25
+ out << ""
26
+
27
+ end
28
+
29
+ end
30
+
31
+ out.join("\n") + "\n"
@@ -0,0 +1 @@
1
+ changelog.to_h.to_json
@@ -0,0 +1,30 @@
1
+ out = []
2
+
3
+ out << "# #{title}"
4
+
5
+ changelog.by_date.each do |date, date_changes|
6
+
7
+ date_changes.by_author.each do |author, author_changes|
8
+
9
+ out << "\n## #{date} #{author}\n"
10
+
11
+ author_changes.each do |entry|
12
+
13
+ out << "* #{entry.message.strip}"
14
+
15
+ if entry.type
16
+ out.last << " [#{entry.type}]"
17
+ end
18
+
19
+ if options.revision
20
+ out.last << " (##{entry.revision})"
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ out.join("\n") + "\n\n"
30
+
@@ -0,0 +1,30 @@
1
+ out = []
2
+
3
+ out << "= #{title}"
4
+
5
+ changelog.by_date.each do |date, date_changes|
6
+
7
+ date_changes.by_author.each do |author, author_changes|
8
+
9
+ out << "\n== #{date} #{author}\n"
10
+
11
+ author_changes.each do |entry|
12
+
13
+ out << "* #{entry.message.strip}"
14
+
15
+ if entry.type
16
+ out.last << " [#{entry.type}]"
17
+ end
18
+
19
+ if options.revision
20
+ out.last << " (##{entry.revision})"
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ out.join("\n") + "\n\n"
30
+
@@ -0,0 +1 @@
1
+ changelog.to_h.to_yaml