vclog 1.5.0 → 1.6.0

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.
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